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