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