708885ba87495c41cf0de1e5fe5bafd78bb01296
[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 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 }
651
652 void silc_sftp_read(SilcSFTP sftp,
653                     SilcSFTPHandle handle,
654                     SilcUInt64 offset, 
655                     SilcUInt32 len,
656                     SilcSFTPDataCallback callback,
657                     void *context)
658 {
659   SilcSFTPClient client = (SilcSFTPClient)sftp;
660   SilcSFTPRequest req;
661   SilcUInt32 len2 = 0;
662   const unsigned char *hdata;
663   SilcUInt32 hdata_len;
664
665   SILC_LOG_DEBUG(("Read request"));
666
667   req = silc_calloc(1, sizeof(*req));
668   if (!req)
669     return;
670   req->id = client->id++;
671   req->type = SILC_SFTP_READ;
672   req->data = callback;
673   req->context = context;
674   silc_list_add(client->requests, req);
675
676   silc_sftp_handle_get(handle, &hdata, &hdata_len);
677   len2 = 4 + 4 + hdata_len + 8 + 4;
678
679   silc_sftp_send_packet(client, req->type, len2, 
680                         SILC_STR_UI_INT(req->id),
681                         SILC_STR_UI_INT(hdata_len),
682                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
683                         SILC_STR_UI_INT64(offset),
684                         SILC_STR_UI_INT(len),
685                         SILC_STR_END);
686 }
687
688 void silc_sftp_write(SilcSFTP sftp,
689                      SilcSFTPHandle handle,
690                      SilcUInt64 offset,
691                      const unsigned char *data,
692                      SilcUInt32 data_len,
693                      SilcSFTPStatusCallback callback,
694                      void *context)
695 {
696   SilcSFTPClient client = (SilcSFTPClient)sftp;
697   SilcSFTPRequest req;
698   SilcUInt32 len = 0;
699   const unsigned char *hdata;
700   SilcUInt32 hdata_len;
701
702   SILC_LOG_DEBUG(("Write request"));
703
704   req = silc_calloc(1, sizeof(*req));
705   if (!req)
706     return;
707   req->id = client->id++;
708   req->type = SILC_SFTP_WRITE;
709   req->status = callback;
710   req->context = context;
711   silc_list_add(client->requests, req);
712
713   silc_sftp_handle_get(handle, &hdata, &hdata_len);
714   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
715
716   silc_sftp_send_packet(client, req->type, len, 
717                         SILC_STR_UI_INT(req->id),
718                         SILC_STR_UI_INT(hdata_len),
719                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
720                         SILC_STR_UI_INT64(offset),
721                         SILC_STR_UI_INT(data_len),
722                         SILC_STR_UI_XNSTRING(data, data_len),
723                         SILC_STR_END);
724 }
725
726 void silc_sftp_remove(SilcSFTP sftp,
727                       const char *filename,
728                       SilcSFTPStatusCallback callback,
729                       void *context)
730 {
731   SilcSFTPClient client = (SilcSFTPClient)sftp;
732   SilcSFTPRequest req;
733   SilcUInt32 len = 0;
734
735   SILC_LOG_DEBUG(("Remove request"));
736
737   req = silc_calloc(1, sizeof(*req));
738   if (!req)
739     return;
740   req->id = client->id++;
741   req->type = SILC_SFTP_REMOVE;
742   req->status = callback;
743   req->context = context;
744   silc_list_add(client->requests, req);
745
746   len = 4 + 4 + strlen(filename);
747
748   silc_sftp_send_packet(client, req->type, len, 
749                         SILC_STR_UI_INT(req->id),
750                         SILC_STR_UI_INT(strlen(filename)),
751                         SILC_STR_UI32_STRING(filename),
752                         SILC_STR_END);
753 }
754
755 void silc_sftp_rename(SilcSFTP sftp,
756                       const char *oldname,
757                       const char *newname,
758                       SilcSFTPStatusCallback callback,
759                       void *context)
760 {
761   SilcSFTPClient client = (SilcSFTPClient)sftp;
762   SilcSFTPRequest req;
763   SilcUInt32 len = 0;
764
765   SILC_LOG_DEBUG(("Rename request"));
766
767   req = silc_calloc(1, sizeof(*req));
768   if (!req)
769     return;
770   req->id = client->id++;
771   req->type = SILC_SFTP_RENAME;
772   req->status = callback;
773   req->context = context;
774   silc_list_add(client->requests, req);
775
776   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
777
778   silc_sftp_send_packet(client, req->type, len, 
779                         SILC_STR_UI_INT(req->id),
780                         SILC_STR_UI_INT(strlen(oldname)),
781                         SILC_STR_UI32_STRING(oldname),
782                         SILC_STR_UI_INT(strlen(newname)),
783                         SILC_STR_UI32_STRING(newname),
784                         SILC_STR_END);
785 }
786
787 void silc_sftp_mkdir(SilcSFTP sftp,
788                      const char *path,
789                      SilcSFTPAttributes attrs,
790                      SilcSFTPStatusCallback callback,
791                      void *context)
792 {
793   SilcSFTPClient client = (SilcSFTPClient)sftp;
794   SilcSFTPRequest req;
795   SilcUInt32 len = 0;
796   SilcBuffer attrs_buf;
797
798   SILC_LOG_DEBUG(("Mkdir request"));
799
800   req = silc_calloc(1, sizeof(*req));
801   if (!req)
802     return;
803   req->id = client->id++;
804   req->type = SILC_SFTP_MKDIR;
805   req->status = callback;
806   req->context = context;
807   silc_list_add(client->requests, req);
808
809   attrs_buf = silc_sftp_attr_encode(attrs);
810   if (!attrs_buf)
811     return;
812   len = 4 + 4 + strlen(path) + attrs_buf->len;
813
814   silc_sftp_send_packet(client, req->type, len, 
815                         SILC_STR_UI_INT(req->id),
816                         SILC_STR_UI_INT(strlen(path)),
817                         SILC_STR_UI32_STRING(path),
818                         SILC_STR_UI_XNSTRING(attrs_buf->data,
819                                              attrs_buf->len),
820                         SILC_STR_END);
821
822   silc_buffer_free(attrs_buf);
823 }
824
825 void silc_sftp_rmdir(SilcSFTP sftp,
826                      const char *path,
827                      SilcSFTPStatusCallback callback,
828                      void *context)
829 {
830   SilcSFTPClient client = (SilcSFTPClient)sftp;
831   SilcSFTPRequest req;
832   SilcUInt32 len = 0;
833
834   SILC_LOG_DEBUG(("Rmdir request"));
835
836   req = silc_calloc(1, sizeof(*req));
837   if (!req)
838     return;
839   req->id = client->id++;
840   req->type = SILC_SFTP_RMDIR;
841   req->status = callback;
842   req->context = context;
843   silc_list_add(client->requests, req);
844
845   len = 4 + 4 + strlen(path);
846
847   silc_sftp_send_packet(client, req->type, len, 
848                         SILC_STR_UI_INT(req->id),
849                         SILC_STR_UI_INT(strlen(path)),
850                         SILC_STR_UI32_STRING(path),
851                         SILC_STR_END);
852 }
853
854 void silc_sftp_opendir(SilcSFTP sftp,
855                        const char *path,
856                        SilcSFTPHandleCallback callback,
857                        void *context)
858 {
859   SilcSFTPClient client = (SilcSFTPClient)sftp;
860   SilcSFTPRequest req;
861   SilcUInt32 len = 0;
862
863   SILC_LOG_DEBUG(("Opendir request"));
864
865   req = silc_calloc(1, sizeof(*req));
866   if (!req)
867     return;
868   req->id = client->id++;
869   req->type = SILC_SFTP_OPENDIR;
870   req->handle = callback;
871   req->context = context;
872   silc_list_add(client->requests, req);
873
874   len = 4 + 4 + strlen(path);
875
876   silc_sftp_send_packet(client, req->type, len, 
877                         SILC_STR_UI_INT(req->id),
878                         SILC_STR_UI_INT(strlen(path)),
879                         SILC_STR_UI32_STRING(path),
880                         SILC_STR_END);
881 }
882
883 void silc_sftp_readdir(SilcSFTP sftp,
884                        SilcSFTPHandle handle,
885                        SilcSFTPNameCallback callback,
886                        void *context)
887 {
888   SilcSFTPClient client = (SilcSFTPClient)sftp;
889   SilcSFTPRequest req;
890   SilcUInt32 len = 0;
891   const unsigned char *hdata;
892   SilcUInt32 hdata_len;
893
894   SILC_LOG_DEBUG(("Readdir request"));
895
896   req = silc_calloc(1, sizeof(*req));
897   if (!req)
898     return;
899   req->id = client->id++;
900   req->type = SILC_SFTP_READDIR;
901   req->name = callback;
902   req->context = context;
903   silc_list_add(client->requests, req);
904
905   silc_sftp_handle_get(handle, &hdata, &hdata_len);
906   len = 4 + 4 + hdata_len;
907
908   silc_sftp_send_packet(client, req->type, len, 
909                         SILC_STR_UI_INT(req->id),
910                         SILC_STR_UI_INT(hdata_len),
911                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
912                         SILC_STR_END);
913 }
914
915 void silc_sftp_stat(SilcSFTP sftp,
916                     const char *path,
917                     SilcSFTPAttrCallback callback,
918                     void *context)
919 {
920   SilcSFTPClient client = (SilcSFTPClient)sftp;
921   SilcSFTPRequest req;
922   SilcUInt32 len = 0;
923
924   SILC_LOG_DEBUG(("Stat request"));
925
926   req = silc_calloc(1, sizeof(*req));
927   if (!req)
928     return;
929   req->id = client->id++;
930   req->type = SILC_SFTP_STAT;
931   req->attr = callback;
932   req->context = context;
933   silc_list_add(client->requests, req);
934
935   len = 4 + 4 + strlen(path);
936
937   silc_sftp_send_packet(client, req->type, len, 
938                         SILC_STR_UI_INT(req->id),
939                         SILC_STR_UI_INT(strlen(path)),
940                         SILC_STR_UI32_STRING(path),
941                         SILC_STR_END);
942 }
943
944 void silc_sftp_lstat(SilcSFTP sftp,
945                      const char *path,
946                      SilcSFTPAttrCallback callback,
947                      void *context)
948 {
949   SilcSFTPClient client = (SilcSFTPClient)sftp;
950   SilcSFTPRequest req;
951   SilcUInt32 len = 0;
952
953   SILC_LOG_DEBUG(("Lstat request"));
954
955   req = silc_calloc(1, sizeof(*req));
956   if (!req)
957     return;
958   req->id = client->id++;
959   req->type = SILC_SFTP_LSTAT;
960   req->attr = callback;
961   req->context = context;
962   silc_list_add(client->requests, req);
963
964   len = 4 + 4 + strlen(path);
965
966   silc_sftp_send_packet(client, req->type, len, 
967                         SILC_STR_UI_INT(req->id),
968                         SILC_STR_UI_INT(strlen(path)),
969                         SILC_STR_UI32_STRING(path),
970                         SILC_STR_END);
971 }
972
973 void silc_sftp_fstat(SilcSFTP sftp,
974                      SilcSFTPHandle handle,
975                      SilcSFTPAttrCallback callback,
976                      void *context)
977 {
978   SilcSFTPClient client = (SilcSFTPClient)sftp;
979   SilcSFTPRequest req;
980   SilcUInt32 len = 0;
981   const unsigned char *hdata;
982   SilcUInt32 hdata_len;
983
984   SILC_LOG_DEBUG(("Fstat request"));
985
986   req = silc_calloc(1, sizeof(*req));
987   if (!req)
988     return;
989   req->id = client->id++;
990   req->type = SILC_SFTP_FSTAT;
991   req->attr = callback;
992   req->context = context;
993   silc_list_add(client->requests, req);
994
995   silc_sftp_handle_get(handle, &hdata, &hdata_len);
996   len = 4 + 4 + hdata_len;
997
998   silc_sftp_send_packet(client, req->type, len, 
999                         SILC_STR_UI_INT(req->id),
1000                         SILC_STR_UI_INT(hdata_len),
1001                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1002                         SILC_STR_END);
1003 }
1004
1005 void silc_sftp_setstat(SilcSFTP sftp,
1006                        const char *path,
1007                        SilcSFTPAttributes attrs,
1008                        SilcSFTPStatusCallback callback,
1009                        void *context)
1010 {
1011   SilcSFTPClient client = (SilcSFTPClient)sftp;
1012   SilcSFTPRequest req;
1013   SilcUInt32 len = 0;
1014   SilcBuffer attrs_buf;
1015
1016   SILC_LOG_DEBUG(("Setstat request"));
1017
1018   req = silc_calloc(1, sizeof(*req));
1019   if (!req)
1020     return;
1021   req->id = client->id++;
1022   req->type = SILC_SFTP_SETSTAT;
1023   req->status = callback;
1024   req->context = context;
1025   silc_list_add(client->requests, req);
1026
1027   attrs_buf = silc_sftp_attr_encode(attrs);
1028   if (!attrs_buf)
1029     return;
1030   len = 4 + 4 + strlen(path) + attrs_buf->len;
1031
1032   silc_sftp_send_packet(client, req->type, len, 
1033                         SILC_STR_UI_INT(req->id),
1034                         SILC_STR_UI_INT(strlen(path)),
1035                         SILC_STR_UI32_STRING(path),
1036                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1037                                              attrs_buf->len),
1038                         SILC_STR_END);
1039
1040   silc_buffer_free(attrs_buf);
1041 }
1042
1043 void silc_sftp_fsetstat(SilcSFTP sftp,
1044                         SilcSFTPHandle handle,
1045                         SilcSFTPAttributes attrs,
1046                         SilcSFTPStatusCallback callback,
1047                         void *context)
1048 {
1049   SilcSFTPClient client = (SilcSFTPClient)sftp;
1050   SilcSFTPRequest req;
1051   SilcUInt32 len = 0;
1052   SilcBuffer attrs_buf;
1053   const unsigned char *hdata;
1054   SilcUInt32 hdata_len;
1055
1056   SILC_LOG_DEBUG(("Fsetstat request"));
1057
1058   req = silc_calloc(1, sizeof(*req));
1059   if (!req)
1060     return;
1061   req->id = client->id++;
1062   req->type = SILC_SFTP_FSETSTAT;
1063   req->status = callback;
1064   req->context = context;
1065   silc_list_add(client->requests, req);
1066
1067   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1068   attrs_buf = silc_sftp_attr_encode(attrs);
1069   if (!attrs_buf)
1070     return;
1071   len = 4 + 4 + hdata_len + attrs_buf->len;
1072
1073   silc_sftp_send_packet(client, req->type, len, 
1074                         SILC_STR_UI_INT(req->id),
1075                         SILC_STR_UI_INT(hdata_len),
1076                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1077                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1078                                              attrs_buf->len),
1079                         SILC_STR_END);
1080
1081   silc_buffer_free(attrs_buf);
1082 }
1083
1084 void silc_sftp_readlink(SilcSFTP sftp,
1085                         const char *path,
1086                         SilcSFTPNameCallback callback,
1087                         void *context)
1088 {
1089   SilcSFTPClient client = (SilcSFTPClient)sftp;
1090   SilcSFTPRequest req;
1091   SilcUInt32 len = 0;
1092
1093   SILC_LOG_DEBUG(("Readlink request"));
1094
1095   req = silc_calloc(1, sizeof(*req));
1096   if (!req)
1097     return;
1098   req->id = client->id++;
1099   req->type = SILC_SFTP_READLINK;
1100   req->name = callback;
1101   req->context = context;
1102   silc_list_add(client->requests, req);
1103
1104   len = 4 + 4 + strlen(path);
1105
1106   silc_sftp_send_packet(client, req->type, len, 
1107                         SILC_STR_UI_INT(req->id),
1108                         SILC_STR_UI_INT(strlen(path)),
1109                         SILC_STR_UI32_STRING(path),
1110                         SILC_STR_END);
1111 }
1112
1113 void silc_sftp_symlink(SilcSFTP sftp,
1114                        const char *linkpath,
1115                        const char *targetpath,
1116                        SilcSFTPStatusCallback callback,
1117                        void *context)
1118 {
1119   SilcSFTPClient client = (SilcSFTPClient)sftp;
1120   SilcSFTPRequest req;
1121   SilcUInt32 len = 0;
1122
1123   SILC_LOG_DEBUG(("Symlink request"));
1124
1125   req = silc_calloc(1, sizeof(*req));
1126   if (!req)
1127     return;
1128   req->id = client->id++;
1129   req->type = SILC_SFTP_SYMLINK;
1130   req->status = callback;
1131   req->context = context;
1132   silc_list_add(client->requests, req);
1133
1134   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1135
1136   silc_sftp_send_packet(client, req->type, len, 
1137                         SILC_STR_UI_INT(req->id),
1138                         SILC_STR_UI_INT(strlen(linkpath)),
1139                         SILC_STR_UI32_STRING(linkpath),
1140                         SILC_STR_UI_INT(strlen(targetpath)),
1141                         SILC_STR_UI32_STRING(targetpath),
1142                         SILC_STR_END);
1143 }
1144
1145 void silc_sftp_realpath(SilcSFTP sftp,
1146                         const char *path,
1147                         SilcSFTPNameCallback callback,
1148                         void *context)
1149 {
1150   SilcSFTPClient client = (SilcSFTPClient)sftp;
1151   SilcSFTPRequest req;
1152   SilcUInt32 len = 0;
1153
1154   SILC_LOG_DEBUG(("Realpath request"));
1155
1156   req = silc_calloc(1, sizeof(*req));
1157   if (!req)
1158     return;
1159   req->id = client->id++;
1160   req->type = SILC_SFTP_REALPATH;
1161   req->name = callback;
1162   req->context = context;
1163   silc_list_add(client->requests, req);
1164
1165   len = 4 + 4 + strlen(path);
1166
1167   silc_sftp_send_packet(client, req->type, len, 
1168                         SILC_STR_UI_INT(req->id),
1169                         SILC_STR_UI_INT(strlen(path)),
1170                         SILC_STR_UI32_STRING(path),
1171                         SILC_STR_END);
1172 }
1173
1174 void silc_sftp_extended(SilcSFTP sftp,
1175                         const char *request,
1176                         const unsigned char *data,
1177                         SilcUInt32 data_len,
1178                         SilcSFTPExtendedCallback callback,
1179                         void *context)
1180 {
1181   SilcSFTPClient client = (SilcSFTPClient)sftp;
1182   SilcSFTPRequest req;
1183   SilcUInt32 len = 0;
1184
1185   SILC_LOG_DEBUG(("Extended request"));
1186
1187   req = silc_calloc(1, sizeof(*req));
1188   if (!req)
1189     return;
1190   req->id = client->id++;
1191   req->type = SILC_SFTP_WRITE;
1192   req->extended = callback;
1193   req->context = context;
1194   silc_list_add(client->requests, req);
1195
1196   len = 4 + 4 + strlen(request) + data_len;
1197
1198   silc_sftp_send_packet(client, req->type, len, 
1199                         SILC_STR_UI_INT(req->id),
1200                         SILC_STR_UI_INT(strlen(request)),
1201                         SILC_STR_UI32_STRING(request),
1202                         SILC_STR_UI_XNSTRING(data, data_len),
1203                         SILC_STR_END);
1204 }