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