Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcsftp / sftp_client.c
1 /*
2
3   sftp_client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 2003 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 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcsftp.h"
23 #include "sftp_util.h"
24
25 /* Request context. Every request will allocate this context and set
26    the correct callback function according the `type' field. */
27 typedef struct SilcSFTPRequestStruct {
28   SilcUInt32 id;
29   SilcSFTPPacket type;
30   SilcSFTPStatusCallback status;
31   SilcSFTPHandleCallback handle;
32   SilcSFTPDataCallback data;
33   SilcSFTPNameCallback name;
34   SilcSFTPAttrCallback attr;
35   SilcSFTPExtendedCallback extended;
36   void *context;
37   struct SilcSFTPRequestStruct *next;
38 } *SilcSFTPRequest;
39
40 /* SFTP client context */
41 typedef struct {
42   SilcSFTPSendPacketCallback send_packet;
43   void *send_context;
44   SilcSFTPVersionCallback version;
45   void *version_context;
46   SilcUInt32 id;
47   SilcList requests;
48   SilcBuffer packet;
49 } *SilcSFTPClient;
50
51 /* File handle */
52 struct SilcSFTPHandleStruct {
53   unsigned char *data;
54   SilcUInt32 data_len;
55 };
56
57 /* Creates SilcSFTPHandle and returns pointer to it. The caller must free
58    the context. */
59
60 static SilcSFTPHandle silc_sftp_handle_create(unsigned char *data,
61                                               SilcUInt32 data_len)
62 {
63   SilcSFTPHandle handle;
64
65   handle = silc_calloc(1, sizeof(*handle));
66   if (!handle)
67     return NULL;
68   handle->data = silc_calloc(data_len, sizeof(*handle->data));
69   if (!handle->data)
70     return NULL;
71   memcpy(handle->data, data, data_len);
72   handle->data_len = data_len;
73
74   return handle;
75 }
76
77 /* Deletes the handle indicated by the `handle'. */
78
79 static void silc_sftp_handle_delete(SilcSFTPHandle handle)
80 {
81   silc_free(handle->data);
82   silc_free(handle);
83 }
84
85 /* Returns the handle data of the `handle' to the `data' pointer. */
86
87 static void silc_sftp_handle_get(SilcSFTPHandle handle,
88                                  const unsigned char **data,
89                                  SilcUInt32 *data_len)
90 {
91   *data = (const unsigned char *)handle->data;
92   *data_len = handle->data_len;
93 }
94
95 /* General routine to send SFTP packet to the SFTP server. */
96
97 static void silc_sftp_send_packet(SilcSFTPClient sftp,
98                                   SilcSFTPPacket type,
99                                   SilcUInt32 len, ...)
100 {
101   SilcBuffer tmp;
102   va_list vp;
103
104   va_start(vp, len);
105   tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
106   va_end(vp);
107   if (!tmp)
108     return;
109   sftp->packet = tmp;
110
111   SILC_LOG_HEXDUMP(("SFTP packet to server"), sftp->packet->data,
112                    sftp->packet->len);
113
114   /* Send the packet */
115   (*sftp->send_packet)(sftp->packet, sftp->send_context);
116
117   /* Clear packet */
118   sftp->packet->data = sftp->packet->tail = sftp->packet->head;
119   sftp->packet->len = 0;
120 }
121
122 /* Finds request by request ID. */
123
124 static SilcSFTPRequest silc_sftp_find_request(SilcSFTPClient sftp, SilcUInt32 id)
125 {
126   SilcSFTPRequest req;
127
128   SILC_LOG_DEBUG(("Finding request ID: %d", id));
129
130   silc_list_start(sftp->requests);
131   while ((req = silc_list_get(sftp->requests)) != SILC_LIST_END) {
132     if (req->id == id)
133       return req;
134   }
135
136   SILC_LOG_DEBUG(("Unknown request ID"));
137
138   return NULL;
139 }
140
141 /* Function used to call the request callback indicated by the `req'. The
142    `status' will be sent to the callback function as the status of the
143    operation. The variable argument list includes the status and req->type
144    specific data. */
145
146 static void silc_sftp_call_request(SilcSFTPClient sftp,
147                                    SilcSFTPRequest req,
148                                    SilcSFTPPacket type,
149                                    SilcSFTPStatus status, ...)
150 {
151   va_list vp;
152
153   SILC_LOG_DEBUG(("Start"));
154
155   va_start(vp, status);
156
157   switch (req->type) {
158   case SILC_SFTP_READ:
159     {
160       /* Data returned */
161       unsigned char *data;
162       SilcUInt32 data_len;
163
164       if (status != SILC_SFTP_STATUS_OK) {
165         if (req->data)
166           (*req->data)((SilcSFTP)sftp, status, NULL, 0, req->context);
167         break;
168       }
169
170       data = (unsigned char *)va_arg(vp, unsigned char *);
171       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
172
173       if (req->data)
174         (*req->data)((SilcSFTP)sftp, status, (const unsigned char *)data,
175                      data_len, req->context);
176     }
177     break;
178
179   case SILC_SFTP_OPEN:
180   case SILC_SFTP_OPENDIR:
181     {
182       /* Handle returned */
183       SilcSFTPHandle handle;
184       unsigned char *hdata;
185       SilcUInt32 hdata_len;
186
187       if (status != SILC_SFTP_STATUS_OK) {
188         if (req->handle)
189           (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
190         break;
191       }
192
193       hdata = (unsigned char *)va_arg(vp, unsigned char *);
194       hdata_len = (SilcUInt32)va_arg(vp, SilcUInt32);
195       handle = silc_sftp_handle_create(hdata, hdata_len);
196       if (!handle) {
197         if (req->handle)
198           (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
199         break;
200       }
201
202       if (req->handle)
203         (*req->handle)((SilcSFTP)sftp, status, handle, req->context);
204     }
205     break;
206
207   case SILC_SFTP_CLOSE:
208   case SILC_SFTP_WRITE:
209   case SILC_SFTP_REMOVE:
210   case SILC_SFTP_RENAME:
211   case SILC_SFTP_MKDIR:
212   case SILC_SFTP_RMDIR:
213   case SILC_SFTP_SETSTAT:
214   case SILC_SFTP_FSETSTAT:
215   case SILC_SFTP_SYMLINK:
216     {
217       /* Status returned */
218       char *message, *language_tag;
219
220       message = (char *)va_arg(vp, char *);
221       language_tag = (char *)va_arg(vp, char *);
222
223       if (req->status)
224         (*req->status)((SilcSFTP)sftp, status, (const char *)message,
225                        (const char *)language_tag, req->context);
226     }
227     break;
228
229   case SILC_SFTP_STAT:
230   case SILC_SFTP_LSTAT:
231   case SILC_SFTP_FSTAT:
232     {
233       /* Attributes returned */
234       SilcSFTPAttributes attr;
235
236       if (status != SILC_SFTP_STATUS_OK) {
237         if (req->attr)
238           (*req->attr)((SilcSFTP)sftp, status, NULL, req->context);
239         break;
240       }
241
242       attr = (SilcSFTPAttributes)va_arg(vp, SilcSFTPAttributes);
243
244       if (req->attr)
245         (*req->attr)((SilcSFTP)sftp, status, (const SilcSFTPAttributes)attr,
246                      req->context);
247     }
248     break;
249
250   case SILC_SFTP_READDIR:
251   case SILC_SFTP_REALPATH:
252   case SILC_SFTP_READLINK:
253     {
254       /* Name(s) returned */
255       SilcSFTPName name;
256
257       if (status != SILC_SFTP_STATUS_OK) {
258         if (req->name)
259           (*req->name)((SilcSFTP)sftp, status, NULL, req->context);
260         break;
261       }
262
263       name = (SilcSFTPName)va_arg(vp, SilcSFTPName);
264
265       if (req->name)
266         (*req->name)((SilcSFTP)sftp, status, name, req->context);
267     }
268     break;
269
270   case SILC_SFTP_EXTENDED:
271     {
272       /* Extended reply returned */
273       unsigned char *data;
274       SilcUInt32 data_len;
275
276       if (status != SILC_SFTP_STATUS_OK) {
277         if (req->extended)
278           (*req->extended)((SilcSFTP)sftp, status, NULL, 0, req->context);
279         break;
280       }
281
282       data = (unsigned char *)va_arg(vp, unsigned char *);
283       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
284
285       if (req->extended)
286         (*req->extended)((SilcSFTP)sftp, status, (const unsigned char *)data,
287                          data_len, req->context);
288     }
289     break;
290
291   default:
292     break;
293   }
294
295   /* Remove this request */
296   silc_list_del(sftp->requests, req);
297   silc_free(req);
298
299   va_end(vp);
300 }
301
302 /* Starts SFTP client and returns context for it.  The version callback
303    indicated by the `callback' will be called after the SFTP session has
304    been started and server has returned the version of the protocol.  The
305    SFTP client context is returned in the callback too.  This returns
306    allocated SFTP client context or NULL on error. */
307
308 SilcSFTP silc_sftp_client_start(SilcSFTPSendPacketCallback send_packet,
309                                 void *send_context,
310                                 SilcSFTPVersionCallback callback,
311                                 void *context)
312 {
313   SilcSFTPClient sftp;
314
315   if (!send_packet)
316     return NULL;
317
318   sftp = silc_calloc(1, sizeof(*sftp));
319   if (!sftp)
320     return NULL;
321   sftp->send_packet = send_packet;
322   sftp->send_context = send_context;
323   sftp->version = callback;
324   sftp->version_context = context;
325   silc_list_init(sftp->requests, struct SilcSFTPRequestStruct, next);
326
327   /* Send the SFTP session initialization to the server */
328   silc_sftp_send_packet(sftp, SILC_SFTP_INIT, 4,
329                         SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
330                         SILC_STR_END);
331
332   return (SilcSFTP)sftp;
333 }
334
335 /* Shutdown's the SFTP client.  The caller is responsible of closing
336    the associated socket connection.  The SFTP context is freed and is
337    invalid after this function returns. */
338
339 void silc_sftp_client_shutdown(SilcSFTP context)
340 {
341   SilcSFTPClient sftp = (SilcSFTPClient)context;
342
343   if (sftp->packet)
344     silc_buffer_free(sftp->packet);
345   silc_free(sftp);
346 }
347
348 /* Function that is called to process the incmoing SFTP packet. */
349 /* XXX Some day this will go away and we have automatic receive callbacks
350    for SilcSocketConnection API or SilcPacketContext API. */
351
352 void silc_sftp_client_receive_process(SilcSFTP context,
353                                       SilcSocketConnection sock,
354                                       SilcPacketContext *packet)
355 {
356   SilcSFTPClient sftp = (SilcSFTPClient)context;
357   SilcSFTPRequest req;
358   SilcSFTPPacket type;
359   const unsigned char *payload = NULL;
360   SilcUInt32 payload_len;
361   int ret;
362   SilcBufferStruct buf;
363   SilcUInt32 id;
364
365   SILC_LOG_DEBUG(("Start"));
366
367   /* Parse the packet */
368   type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
369                                  &payload_len);
370   if (!type)
371     return;
372
373   silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
374
375   switch (type) {
376   case SILC_SFTP_VERSION:
377     {
378       SilcSFTPVersion version;
379
380       SILC_LOG_DEBUG(("Version packet"));
381
382       ret = silc_buffer_unformat(&buf,
383                                  SILC_STR_UI_INT(&version),
384                                  SILC_STR_END);
385       if (ret < 0) {
386         (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0,
387                          sftp->version_context);
388         break;
389       }
390
391       /* Call the callback */
392       (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version,
393                        sftp->version_context);
394     }
395     break;
396
397   case SILC_SFTP_STATUS:
398     {
399       SilcUInt32 status;
400       char *message = NULL, *language_tag = NULL;
401
402       SILC_LOG_DEBUG(("Status packet"));
403
404       ret = silc_buffer_unformat(&buf,
405                                  SILC_STR_UI_INT(&id),
406                                  SILC_STR_UI_INT(&status),
407                                  SILC_STR_END);
408       if (ret < 0)
409         break;
410
411       if (status != SILC_SFTP_STATUS_OK) {
412         silc_buffer_pull(&buf, 8);
413         ret = silc_buffer_unformat(&buf,
414                                    SILC_STR_UI32_STRING_ALLOC(&message),
415                                    SILC_STR_UI32_STRING_ALLOC(&language_tag),
416                                    SILC_STR_END);
417         if (ret < 0)
418           break;
419
420         silc_buffer_push(&buf, 8);
421       }
422
423       /* Get request */
424       req = silc_sftp_find_request(sftp, id);
425       if (!req) {
426         silc_free(message);
427         silc_free(language_tag);
428         break;
429       }
430
431       /* Call the callback */
432       silc_sftp_call_request(sftp, req, type, status, message, language_tag);
433
434       silc_free(message);
435       silc_free(language_tag);
436     }
437     break;
438
439   case SILC_SFTP_HANDLE:
440     {
441       unsigned char *handle = NULL;
442       SilcUInt32 handle_len;
443
444       SILC_LOG_DEBUG(("Handle packet"));
445
446       ret = silc_buffer_unformat(&buf,
447                                  SILC_STR_UI_INT(&id),
448                                  SILC_STR_UI32_NSTRING(&handle,
449                                                        &handle_len),
450                                  SILC_STR_END);
451       if (ret < 0)
452         break;
453
454       /* Get request */
455       req = silc_sftp_find_request(sftp, id);
456       if (!req)
457         break;
458
459       /* Call the callback */
460       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
461                              handle, handle_len);
462     }
463     break;
464
465   case SILC_SFTP_DATA:
466     {
467       unsigned char *data = NULL;
468       SilcUInt32 data_len = 0;
469
470       SILC_LOG_DEBUG(("Data packet"));
471
472       ret = silc_buffer_unformat(&buf,
473                                  SILC_STR_UI_INT(&id),
474                                  SILC_STR_UI32_NSTRING(&data, &data_len),
475                                  SILC_STR_END);
476       if (ret < 0)
477         break;
478
479       /* Get request */
480       req = silc_sftp_find_request(sftp, id);
481       if (!req)
482         break;
483
484       /* Call the callback */
485       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
486                              data, data_len);
487     }
488     break;
489
490   case SILC_SFTP_NAME:
491     {
492       SilcUInt32 count;
493       SilcSFTPName name = NULL;
494
495       SILC_LOG_DEBUG(("Name packet"));
496
497       ret = silc_buffer_unformat(&buf,
498                                  SILC_STR_UI_INT(&id),
499                                  SILC_STR_UI_INT(&count),
500                                  SILC_STR_END);
501       if (ret < 0)
502         break;
503
504       /* Get request */
505       req = silc_sftp_find_request(sftp, id);
506       if (!req)
507         break;
508
509       silc_buffer_pull(&buf, 8);
510       name = silc_sftp_name_decode(count, &buf);
511       if (!name)
512         break;
513       silc_buffer_push(&buf, 8);
514
515       /* Call the callback */
516       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, name);
517       silc_sftp_name_free(name);
518     }
519     break;
520
521   case SILC_SFTP_ATTRS:
522     {
523       SilcSFTPAttributes attr = NULL;
524       unsigned char *data;
525       SilcBufferStruct tmpbuf;
526
527       SILC_LOG_DEBUG(("Attributes packet"));
528
529       ret = silc_buffer_unformat(&buf,
530                                  SILC_STR_UI_INT(&id),
531                                  SILC_STR_UI_XNSTRING(&data, buf.len - 4),
532                                  SILC_STR_END);
533       if (ret < 0)
534         break;
535
536       /* Get request */
537       req = silc_sftp_find_request(sftp, id);
538       if (!req)
539         break;
540
541       silc_buffer_set(&tmpbuf, data, buf.len - 4);
542       attr = silc_sftp_attr_decode(&tmpbuf);
543       if (!attr)
544         break;
545
546       /* Call the callback */
547       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, attr);
548     }
549     break;
550
551   case SILC_SFTP_EXTENDED_REPLY:
552     {
553       unsigned char *data = NULL;
554
555       SILC_LOG_DEBUG(("Extended reply packet"));
556
557       ret = silc_buffer_unformat(&buf,
558                                  SILC_STR_UI_INT(&id),
559                                  SILC_STR_UI_XNSTRING(&data, buf.len - 4),
560                                  SILC_STR_END);
561       if (ret < 0)
562         break;
563
564       /* Get request */
565       req = silc_sftp_find_request(sftp, id);
566       if (!req)
567         break;
568
569       /* Call the callback */
570       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
571                              data, buf.len - 4);
572     }
573     break;
574
575   default:
576     break;
577   }
578 }
579
580 void silc_sftp_open(SilcSFTP sftp,
581                     const char *filename,
582                     SilcSFTPFileOperation pflags,
583                     SilcSFTPAttributes attrs,
584                     SilcSFTPHandleCallback callback,
585                     void *context)
586 {
587   SilcSFTPClient client = (SilcSFTPClient)sftp;
588   SilcSFTPRequest req;
589   SilcBuffer attrs_buf;
590   SilcUInt32 len = 0;
591
592   SILC_LOG_DEBUG(("Open request"));
593
594   req = silc_calloc(1, sizeof(*req));
595   if (!req)
596     return;
597   req->id = client->id++;
598   req->type = SILC_SFTP_OPEN;
599   req->handle = callback;
600   req->context = context;
601   silc_list_add(client->requests, req);
602
603   attrs_buf = silc_sftp_attr_encode(attrs);
604   if (!attrs_buf)
605     return;
606   len = 4 + 4 + strlen(filename) + 4 + attrs_buf->len;
607
608   silc_sftp_send_packet(client, req->type, len,
609                         SILC_STR_UI_INT(req->id),
610                         SILC_STR_UI_INT(strlen(filename)),
611                         SILC_STR_UI32_STRING(filename),
612                         SILC_STR_UI_INT(pflags),
613                         SILC_STR_UI_XNSTRING(attrs_buf->data,
614                                              attrs_buf->len),
615                         SILC_STR_END);
616
617   silc_buffer_free(attrs_buf);
618 }
619
620 void silc_sftp_close(SilcSFTP sftp,
621                      SilcSFTPHandle handle,
622                      SilcSFTPStatusCallback callback,
623                      void *context)
624 {
625   SilcSFTPClient client = (SilcSFTPClient)sftp;
626   SilcSFTPRequest req;
627   SilcUInt32 len = 0;
628   const unsigned char *hdata;
629   SilcUInt32 hdata_len;
630
631   SILC_LOG_DEBUG(("Close request"));
632
633   req = silc_calloc(1, sizeof(*req));
634   if (!req)
635     return;
636   req->id = client->id++;
637   req->type = SILC_SFTP_CLOSE;
638   req->status = callback;
639   req->context = context;
640   silc_list_add(client->requests, req);
641
642   silc_sftp_handle_get(handle, &hdata, &hdata_len);
643   len = 4 + 4 + hdata_len;
644
645   silc_sftp_send_packet(client, req->type, len,
646                         SILC_STR_UI_INT(req->id),
647                         SILC_STR_UI_INT(hdata_len),
648                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
649                         SILC_STR_END);
650   silc_sftp_handle_delete(handle);
651 }
652
653 void silc_sftp_read(SilcSFTP sftp,
654                     SilcSFTPHandle handle,
655                     SilcUInt64 offset,
656                     SilcUInt32 len,
657                     SilcSFTPDataCallback callback,
658                     void *context)
659 {
660   SilcSFTPClient client = (SilcSFTPClient)sftp;
661   SilcSFTPRequest req;
662   SilcUInt32 len2 = 0;
663   const unsigned char *hdata;
664   SilcUInt32 hdata_len;
665
666   SILC_LOG_DEBUG(("Read request"));
667
668   req = silc_calloc(1, sizeof(*req));
669   if (!req)
670     return;
671   req->id = client->id++;
672   req->type = SILC_SFTP_READ;
673   req->data = callback;
674   req->context = context;
675   silc_list_add(client->requests, req);
676
677   silc_sftp_handle_get(handle, &hdata, &hdata_len);
678   len2 = 4 + 4 + hdata_len + 8 + 4;
679
680   silc_sftp_send_packet(client, req->type, len2,
681                         SILC_STR_UI_INT(req->id),
682                         SILC_STR_UI_INT(hdata_len),
683                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
684                         SILC_STR_UI_INT64(offset),
685                         SILC_STR_UI_INT(len),
686                         SILC_STR_END);
687 }
688
689 void silc_sftp_write(SilcSFTP sftp,
690                      SilcSFTPHandle handle,
691                      SilcUInt64 offset,
692                      const unsigned char *data,
693                      SilcUInt32 data_len,
694                      SilcSFTPStatusCallback callback,
695                      void *context)
696 {
697   SilcSFTPClient client = (SilcSFTPClient)sftp;
698   SilcSFTPRequest req;
699   SilcUInt32 len = 0;
700   const unsigned char *hdata;
701   SilcUInt32 hdata_len;
702
703   SILC_LOG_DEBUG(("Write request"));
704
705   req = silc_calloc(1, sizeof(*req));
706   if (!req)
707     return;
708   req->id = client->id++;
709   req->type = SILC_SFTP_WRITE;
710   req->status = callback;
711   req->context = context;
712   silc_list_add(client->requests, req);
713
714   silc_sftp_handle_get(handle, &hdata, &hdata_len);
715   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
716
717   silc_sftp_send_packet(client, req->type, len,
718                         SILC_STR_UI_INT(req->id),
719                         SILC_STR_UI_INT(hdata_len),
720                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
721                         SILC_STR_UI_INT64(offset),
722                         SILC_STR_UI_INT(data_len),
723                         SILC_STR_UI_XNSTRING(data, data_len),
724                         SILC_STR_END);
725 }
726
727 void silc_sftp_remove(SilcSFTP sftp,
728                       const char *filename,
729                       SilcSFTPStatusCallback callback,
730                       void *context)
731 {
732   SilcSFTPClient client = (SilcSFTPClient)sftp;
733   SilcSFTPRequest req;
734   SilcUInt32 len = 0;
735
736   SILC_LOG_DEBUG(("Remove request"));
737
738   req = silc_calloc(1, sizeof(*req));
739   if (!req)
740     return;
741   req->id = client->id++;
742   req->type = SILC_SFTP_REMOVE;
743   req->status = callback;
744   req->context = context;
745   silc_list_add(client->requests, req);
746
747   len = 4 + 4 + strlen(filename);
748
749   silc_sftp_send_packet(client, req->type, len,
750                         SILC_STR_UI_INT(req->id),
751                         SILC_STR_UI_INT(strlen(filename)),
752                         SILC_STR_UI32_STRING(filename),
753                         SILC_STR_END);
754 }
755
756 void silc_sftp_rename(SilcSFTP sftp,
757                       const char *oldname,
758                       const char *newname,
759                       SilcSFTPStatusCallback callback,
760                       void *context)
761 {
762   SilcSFTPClient client = (SilcSFTPClient)sftp;
763   SilcSFTPRequest req;
764   SilcUInt32 len = 0;
765
766   SILC_LOG_DEBUG(("Rename request"));
767
768   req = silc_calloc(1, sizeof(*req));
769   if (!req)
770     return;
771   req->id = client->id++;
772   req->type = SILC_SFTP_RENAME;
773   req->status = callback;
774   req->context = context;
775   silc_list_add(client->requests, req);
776
777   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
778
779   silc_sftp_send_packet(client, req->type, len,
780                         SILC_STR_UI_INT(req->id),
781                         SILC_STR_UI_INT(strlen(oldname)),
782                         SILC_STR_UI32_STRING(oldname),
783                         SILC_STR_UI_INT(strlen(newname)),
784                         SILC_STR_UI32_STRING(newname),
785                         SILC_STR_END);
786 }
787
788 void silc_sftp_mkdir(SilcSFTP sftp,
789                      const char *path,
790                      SilcSFTPAttributes attrs,
791                      SilcSFTPStatusCallback callback,
792                      void *context)
793 {
794   SilcSFTPClient client = (SilcSFTPClient)sftp;
795   SilcSFTPRequest req;
796   SilcUInt32 len = 0;
797   SilcBuffer attrs_buf;
798
799   SILC_LOG_DEBUG(("Mkdir request"));
800
801   req = silc_calloc(1, sizeof(*req));
802   if (!req)
803     return;
804   req->id = client->id++;
805   req->type = SILC_SFTP_MKDIR;
806   req->status = callback;
807   req->context = context;
808   silc_list_add(client->requests, req);
809
810   attrs_buf = silc_sftp_attr_encode(attrs);
811   if (!attrs_buf)
812     return;
813   len = 4 + 4 + strlen(path) + attrs_buf->len;
814
815   silc_sftp_send_packet(client, req->type, len,
816                         SILC_STR_UI_INT(req->id),
817                         SILC_STR_UI_INT(strlen(path)),
818                         SILC_STR_UI32_STRING(path),
819                         SILC_STR_UI_XNSTRING(attrs_buf->data,
820                                              attrs_buf->len),
821                         SILC_STR_END);
822
823   silc_buffer_free(attrs_buf);
824 }
825
826 void silc_sftp_rmdir(SilcSFTP sftp,
827                      const char *path,
828                      SilcSFTPStatusCallback callback,
829                      void *context)
830 {
831   SilcSFTPClient client = (SilcSFTPClient)sftp;
832   SilcSFTPRequest req;
833   SilcUInt32 len = 0;
834
835   SILC_LOG_DEBUG(("Rmdir request"));
836
837   req = silc_calloc(1, sizeof(*req));
838   if (!req)
839     return;
840   req->id = client->id++;
841   req->type = SILC_SFTP_RMDIR;
842   req->status = callback;
843   req->context = context;
844   silc_list_add(client->requests, req);
845
846   len = 4 + 4 + strlen(path);
847
848   silc_sftp_send_packet(client, req->type, len,
849                         SILC_STR_UI_INT(req->id),
850                         SILC_STR_UI_INT(strlen(path)),
851                         SILC_STR_UI32_STRING(path),
852                         SILC_STR_END);
853 }
854
855 void silc_sftp_opendir(SilcSFTP sftp,
856                        const char *path,
857                        SilcSFTPHandleCallback callback,
858                        void *context)
859 {
860   SilcSFTPClient client = (SilcSFTPClient)sftp;
861   SilcSFTPRequest req;
862   SilcUInt32 len = 0;
863
864   SILC_LOG_DEBUG(("Opendir request"));
865
866   req = silc_calloc(1, sizeof(*req));
867   if (!req)
868     return;
869   req->id = client->id++;
870   req->type = SILC_SFTP_OPENDIR;
871   req->handle = callback;
872   req->context = context;
873   silc_list_add(client->requests, req);
874
875   len = 4 + 4 + strlen(path);
876
877   silc_sftp_send_packet(client, req->type, len,
878                         SILC_STR_UI_INT(req->id),
879                         SILC_STR_UI_INT(strlen(path)),
880                         SILC_STR_UI32_STRING(path),
881                         SILC_STR_END);
882 }
883
884 void silc_sftp_readdir(SilcSFTP sftp,
885                        SilcSFTPHandle handle,
886                        SilcSFTPNameCallback callback,
887                        void *context)
888 {
889   SilcSFTPClient client = (SilcSFTPClient)sftp;
890   SilcSFTPRequest req;
891   SilcUInt32 len = 0;
892   const unsigned char *hdata;
893   SilcUInt32 hdata_len;
894
895   SILC_LOG_DEBUG(("Readdir request"));
896
897   req = silc_calloc(1, sizeof(*req));
898   if (!req)
899     return;
900   req->id = client->id++;
901   req->type = SILC_SFTP_READDIR;
902   req->name = callback;
903   req->context = context;
904   silc_list_add(client->requests, req);
905
906   silc_sftp_handle_get(handle, &hdata, &hdata_len);
907   len = 4 + 4 + hdata_len;
908
909   silc_sftp_send_packet(client, req->type, len,
910                         SILC_STR_UI_INT(req->id),
911                         SILC_STR_UI_INT(hdata_len),
912                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
913                         SILC_STR_END);
914 }
915
916 void silc_sftp_stat(SilcSFTP sftp,
917                     const char *path,
918                     SilcSFTPAttrCallback callback,
919                     void *context)
920 {
921   SilcSFTPClient client = (SilcSFTPClient)sftp;
922   SilcSFTPRequest req;
923   SilcUInt32 len = 0;
924
925   SILC_LOG_DEBUG(("Stat request"));
926
927   req = silc_calloc(1, sizeof(*req));
928   if (!req)
929     return;
930   req->id = client->id++;
931   req->type = SILC_SFTP_STAT;
932   req->attr = callback;
933   req->context = context;
934   silc_list_add(client->requests, req);
935
936   len = 4 + 4 + strlen(path);
937
938   silc_sftp_send_packet(client, req->type, len,
939                         SILC_STR_UI_INT(req->id),
940                         SILC_STR_UI_INT(strlen(path)),
941                         SILC_STR_UI32_STRING(path),
942                         SILC_STR_END);
943 }
944
945 void silc_sftp_lstat(SilcSFTP sftp,
946                      const char *path,
947                      SilcSFTPAttrCallback callback,
948                      void *context)
949 {
950   SilcSFTPClient client = (SilcSFTPClient)sftp;
951   SilcSFTPRequest req;
952   SilcUInt32 len = 0;
953
954   SILC_LOG_DEBUG(("Lstat request"));
955
956   req = silc_calloc(1, sizeof(*req));
957   if (!req)
958     return;
959   req->id = client->id++;
960   req->type = SILC_SFTP_LSTAT;
961   req->attr = callback;
962   req->context = context;
963   silc_list_add(client->requests, req);
964
965   len = 4 + 4 + strlen(path);
966
967   silc_sftp_send_packet(client, req->type, len,
968                         SILC_STR_UI_INT(req->id),
969                         SILC_STR_UI_INT(strlen(path)),
970                         SILC_STR_UI32_STRING(path),
971                         SILC_STR_END);
972 }
973
974 void silc_sftp_fstat(SilcSFTP sftp,
975                      SilcSFTPHandle handle,
976                      SilcSFTPAttrCallback callback,
977                      void *context)
978 {
979   SilcSFTPClient client = (SilcSFTPClient)sftp;
980   SilcSFTPRequest req;
981   SilcUInt32 len = 0;
982   const unsigned char *hdata;
983   SilcUInt32 hdata_len;
984
985   SILC_LOG_DEBUG(("Fstat request"));
986
987   req = silc_calloc(1, sizeof(*req));
988   if (!req)
989     return;
990   req->id = client->id++;
991   req->type = SILC_SFTP_FSTAT;
992   req->attr = callback;
993   req->context = context;
994   silc_list_add(client->requests, req);
995
996   silc_sftp_handle_get(handle, &hdata, &hdata_len);
997   len = 4 + 4 + hdata_len;
998
999   silc_sftp_send_packet(client, req->type, len,
1000                         SILC_STR_UI_INT(req->id),
1001                         SILC_STR_UI_INT(hdata_len),
1002                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1003                         SILC_STR_END);
1004 }
1005
1006 void silc_sftp_setstat(SilcSFTP sftp,
1007                        const char *path,
1008                        SilcSFTPAttributes attrs,
1009                        SilcSFTPStatusCallback callback,
1010                        void *context)
1011 {
1012   SilcSFTPClient client = (SilcSFTPClient)sftp;
1013   SilcSFTPRequest req;
1014   SilcUInt32 len = 0;
1015   SilcBuffer attrs_buf;
1016
1017   SILC_LOG_DEBUG(("Setstat request"));
1018
1019   req = silc_calloc(1, sizeof(*req));
1020   if (!req)
1021     return;
1022   req->id = client->id++;
1023   req->type = SILC_SFTP_SETSTAT;
1024   req->status = callback;
1025   req->context = context;
1026   silc_list_add(client->requests, req);
1027
1028   attrs_buf = silc_sftp_attr_encode(attrs);
1029   if (!attrs_buf)
1030     return;
1031   len = 4 + 4 + strlen(path) + attrs_buf->len;
1032
1033   silc_sftp_send_packet(client, req->type, len,
1034                         SILC_STR_UI_INT(req->id),
1035                         SILC_STR_UI_INT(strlen(path)),
1036                         SILC_STR_UI32_STRING(path),
1037                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1038                                              attrs_buf->len),
1039                         SILC_STR_END);
1040
1041   silc_buffer_free(attrs_buf);
1042 }
1043
1044 void silc_sftp_fsetstat(SilcSFTP sftp,
1045                         SilcSFTPHandle handle,
1046                         SilcSFTPAttributes attrs,
1047                         SilcSFTPStatusCallback callback,
1048                         void *context)
1049 {
1050   SilcSFTPClient client = (SilcSFTPClient)sftp;
1051   SilcSFTPRequest req;
1052   SilcUInt32 len = 0;
1053   SilcBuffer attrs_buf;
1054   const unsigned char *hdata;
1055   SilcUInt32 hdata_len;
1056
1057   SILC_LOG_DEBUG(("Fsetstat request"));
1058
1059   req = silc_calloc(1, sizeof(*req));
1060   if (!req)
1061     return;
1062   req->id = client->id++;
1063   req->type = SILC_SFTP_FSETSTAT;
1064   req->status = callback;
1065   req->context = context;
1066   silc_list_add(client->requests, req);
1067
1068   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1069   attrs_buf = silc_sftp_attr_encode(attrs);
1070   if (!attrs_buf)
1071     return;
1072   len = 4 + 4 + hdata_len + attrs_buf->len;
1073
1074   silc_sftp_send_packet(client, req->type, len,
1075                         SILC_STR_UI_INT(req->id),
1076                         SILC_STR_UI_INT(hdata_len),
1077                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1078                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1079                                              attrs_buf->len),
1080                         SILC_STR_END);
1081
1082   silc_buffer_free(attrs_buf);
1083 }
1084
1085 void silc_sftp_readlink(SilcSFTP sftp,
1086                         const char *path,
1087                         SilcSFTPNameCallback callback,
1088                         void *context)
1089 {
1090   SilcSFTPClient client = (SilcSFTPClient)sftp;
1091   SilcSFTPRequest req;
1092   SilcUInt32 len = 0;
1093
1094   SILC_LOG_DEBUG(("Readlink request"));
1095
1096   req = silc_calloc(1, sizeof(*req));
1097   if (!req)
1098     return;
1099   req->id = client->id++;
1100   req->type = SILC_SFTP_READLINK;
1101   req->name = callback;
1102   req->context = context;
1103   silc_list_add(client->requests, req);
1104
1105   len = 4 + 4 + strlen(path);
1106
1107   silc_sftp_send_packet(client, req->type, len,
1108                         SILC_STR_UI_INT(req->id),
1109                         SILC_STR_UI_INT(strlen(path)),
1110                         SILC_STR_UI32_STRING(path),
1111                         SILC_STR_END);
1112 }
1113
1114 void silc_sftp_symlink(SilcSFTP sftp,
1115                        const char *linkpath,
1116                        const char *targetpath,
1117                        SilcSFTPStatusCallback callback,
1118                        void *context)
1119 {
1120   SilcSFTPClient client = (SilcSFTPClient)sftp;
1121   SilcSFTPRequest req;
1122   SilcUInt32 len = 0;
1123
1124   SILC_LOG_DEBUG(("Symlink request"));
1125
1126   req = silc_calloc(1, sizeof(*req));
1127   if (!req)
1128     return;
1129   req->id = client->id++;
1130   req->type = SILC_SFTP_SYMLINK;
1131   req->status = callback;
1132   req->context = context;
1133   silc_list_add(client->requests, req);
1134
1135   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1136
1137   silc_sftp_send_packet(client, req->type, len,
1138                         SILC_STR_UI_INT(req->id),
1139                         SILC_STR_UI_INT(strlen(linkpath)),
1140                         SILC_STR_UI32_STRING(linkpath),
1141                         SILC_STR_UI_INT(strlen(targetpath)),
1142                         SILC_STR_UI32_STRING(targetpath),
1143                         SILC_STR_END);
1144 }
1145
1146 void silc_sftp_realpath(SilcSFTP sftp,
1147                         const char *path,
1148                         SilcSFTPNameCallback callback,
1149                         void *context)
1150 {
1151   SilcSFTPClient client = (SilcSFTPClient)sftp;
1152   SilcSFTPRequest req;
1153   SilcUInt32 len = 0;
1154
1155   SILC_LOG_DEBUG(("Realpath request"));
1156
1157   req = silc_calloc(1, sizeof(*req));
1158   if (!req)
1159     return;
1160   req->id = client->id++;
1161   req->type = SILC_SFTP_REALPATH;
1162   req->name = callback;
1163   req->context = context;
1164   silc_list_add(client->requests, req);
1165
1166   len = 4 + 4 + strlen(path);
1167
1168   silc_sftp_send_packet(client, req->type, len,
1169                         SILC_STR_UI_INT(req->id),
1170                         SILC_STR_UI_INT(strlen(path)),
1171                         SILC_STR_UI32_STRING(path),
1172                         SILC_STR_END);
1173 }
1174
1175 void silc_sftp_extended(SilcSFTP sftp,
1176                         const char *request,
1177                         const unsigned char *data,
1178                         SilcUInt32 data_len,
1179                         SilcSFTPExtendedCallback callback,
1180                         void *context)
1181 {
1182   SilcSFTPClient client = (SilcSFTPClient)sftp;
1183   SilcSFTPRequest req;
1184   SilcUInt32 len = 0;
1185
1186   SILC_LOG_DEBUG(("Extended request"));
1187
1188   req = silc_calloc(1, sizeof(*req));
1189   if (!req)
1190     return;
1191   req->id = client->id++;
1192   req->type = SILC_SFTP_WRITE;
1193   req->extended = callback;
1194   req->context = context;
1195   silc_list_add(client->requests, req);
1196
1197   len = 4 + 4 + strlen(request) + data_len;
1198
1199   silc_sftp_send_packet(client, req->type, len,
1200                         SILC_STR_UI_INT(req->id),
1201                         SILC_STR_UI_INT(strlen(request)),
1202                         SILC_STR_UI32_STRING(request),
1203                         SILC_STR_UI_XNSTRING(data, data_len),
1204                         SILC_STR_END);
1205 }