Integer type name change.
[silc.git] / lib / silcsftp / sftp_client.c
1 /*
2
3   sftp_client.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcsftp.h"
23 #include "sftp_util.h"
24
25 /* Request context. Every request will allocate this context and set
26    the correct callback function according the `type' field. */
27 typedef struct SilcSFTPRequestStruct {
28   SilcUInt32 id;
29   SilcSFTPPacket type;
30   SilcSFTPStatusCallback status;
31   SilcSFTPHandleCallback handle;
32   SilcSFTPDataCallback data;
33   SilcSFTPNameCallback name;
34   SilcSFTPAttrCallback attr;
35   SilcSFTPExtendedCallback extended;
36   void *context;
37   struct SilcSFTPRequestStruct *next;
38 } *SilcSFTPRequest;
39
40 /* SFTP client context */
41 typedef struct {
42   SilcSocketConnection sock;
43   SilcSFTPSendPacketCallback send_packet;
44   void *send_context;
45   SilcSFTPVersionCallback version;
46   void *version_context;
47   SilcUInt32 id;
48   SilcList requests;
49   SilcBuffer packet;
50 } *SilcSFTPClient;
51
52 /* File handle */
53 struct SilcSFTPHandleStruct {
54   unsigned char *data;
55   SilcUInt32 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                                               SilcUInt32 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                                  SilcUInt32 *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                                   SilcUInt32 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, SilcUInt32 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       SilcUInt32 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 = (SilcUInt32)va_arg(vp, SilcUInt32);
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       SilcUInt32 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 = (SilcUInt32)va_arg(vp, SilcUInt32);
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       SilcUInt32 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 = (SilcUInt32)va_arg(vp, SilcUInt32);
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   if (sftp->packet)
337     silc_buffer_free(sftp->packet);
338   silc_free(sftp);
339 }
340
341 /* Function that is called to process the incmoing SFTP packet. */
342 /* XXX Some day this will go away and we have automatic receive callbacks
343    for SilcSocketConnection API or SilcPacketContext API. */
344
345 void silc_sftp_client_receive_process(SilcSFTP context,
346                                       SilcSocketConnection sock,
347                                       SilcPacketContext *packet)
348 {
349   SilcSFTPClient sftp = (SilcSFTPClient)context;
350   SilcSFTPRequest req;
351   SilcSFTPPacket type;
352   const unsigned char *payload = NULL;
353   SilcUInt32 payload_len;
354   int ret;
355   SilcBufferStruct buf;
356   SilcUInt32 id;
357
358   SILC_LOG_DEBUG(("Start"));
359
360   /* Parse the packet */
361   type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload, 
362                                  &payload_len);
363   if (!type)
364     return;
365
366   silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
367
368   switch (type) {
369   case SILC_SFTP_VERSION:
370     {
371       SilcSFTPVersion version;
372
373       SILC_LOG_DEBUG(("Version packet"));
374
375       ret = silc_buffer_unformat(&buf,
376                                  SILC_STR_UI_INT(&version),
377                                  SILC_STR_END);
378       if (ret < 0) {
379         (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0, 
380                          sftp->version_context);
381         break;
382       }
383
384       /* Call the callback */
385       (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version, 
386                        sftp->version_context);
387     }
388     break;
389
390   case SILC_SFTP_STATUS:
391     {
392       SilcUInt32 status;
393       char *message = NULL, *language_tag = NULL;
394
395       SILC_LOG_DEBUG(("Status packet"));
396
397       ret = silc_buffer_unformat(&buf, 
398                                  SILC_STR_UI_INT(&id),
399                                  SILC_STR_UI_INT(&status),
400                                  SILC_STR_END);
401       if (ret < 0)
402         break;
403
404       if (status != SILC_SFTP_STATUS_OK) {
405         silc_buffer_pull(&buf, 8);
406         ret = silc_buffer_unformat(&buf,
407                                    SILC_STR_UI32_STRING_ALLOC(&message),
408                                    SILC_STR_UI32_STRING_ALLOC(&language_tag),
409                                    SILC_STR_END);
410         if (ret < 0)
411           break;
412
413         silc_buffer_push(&buf, 8);
414       }
415
416       /* Get request */
417       req = silc_sftp_find_request(sftp, id);
418       if (!req) {
419         silc_free(message);
420         silc_free(language_tag);
421         break;
422       }
423
424       /* Call the callback */
425       silc_sftp_call_request(sftp, req, type, status, message, language_tag);
426
427       silc_free(message);
428       silc_free(language_tag);
429     }
430     break;
431
432   case SILC_SFTP_HANDLE:
433     {
434       unsigned char *handle = NULL;
435       SilcUInt32 handle_len;
436
437       SILC_LOG_DEBUG(("Handle packet"));
438
439       ret = silc_buffer_unformat(&buf, 
440                                  SILC_STR_UI_INT(&id),
441                                  SILC_STR_UI32_NSTRING(&handle, 
442                                                        &handle_len),
443                                  SILC_STR_END);
444       if (ret < 0)
445         break;
446
447       /* Get request */
448       req = silc_sftp_find_request(sftp, id);
449       if (!req)
450         break;
451
452       /* Call the callback */
453       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, 
454                              handle, handle_len);
455     }
456     break;
457
458   case SILC_SFTP_DATA:
459     {
460       unsigned char *data = NULL;
461       SilcUInt32 data_len = 0;
462
463       SILC_LOG_DEBUG(("Data packet"));
464
465       ret = silc_buffer_unformat(&buf, 
466                                  SILC_STR_UI_INT(&id),
467                                  SILC_STR_UI32_NSTRING(&data, &data_len),
468                                  SILC_STR_END);
469       if (ret < 0)
470         break;
471
472       /* Get request */
473       req = silc_sftp_find_request(sftp, id);
474       if (!req)
475         break;
476
477       /* Call the callback */
478       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, 
479                              data, data_len);
480     }
481     break;
482
483   case SILC_SFTP_NAME:
484     {
485       SilcUInt32 count;
486       SilcSFTPName name = NULL;
487
488       SILC_LOG_DEBUG(("Name packet"));
489
490       ret = silc_buffer_unformat(&buf, 
491                                  SILC_STR_UI_INT(&id),
492                                  SILC_STR_UI_INT(&count),
493                                  SILC_STR_END);
494       if (ret < 0)
495         break;
496
497       /* Get request */
498       req = silc_sftp_find_request(sftp, id);
499       if (!req)
500         break;
501
502       silc_buffer_pull(&buf, 8);
503       name = silc_sftp_name_decode(count, &buf);
504       if (!name)
505         break;
506       silc_buffer_push(&buf, 8);
507
508       /* Call the callback */
509       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, name);
510       silc_sftp_name_free(name);
511     }
512     break;
513
514   case SILC_SFTP_ATTRS:
515     {
516       SilcSFTPAttributes attr = NULL;
517       unsigned char *data;
518       SilcBufferStruct tmpbuf;
519
520       SILC_LOG_DEBUG(("Attributes packet"));
521
522       ret = silc_buffer_unformat(&buf, 
523                                  SILC_STR_UI_INT(&id),
524                                  SILC_STR_UI_XNSTRING(&data, buf.len - 4),
525                                  SILC_STR_END);
526       if (ret < 0)
527         break;
528
529       /* Get request */
530       req = silc_sftp_find_request(sftp, id);
531       if (!req)
532         break;
533
534       silc_buffer_set(&tmpbuf, data, buf.len - 4);
535       attr = silc_sftp_attr_decode(&tmpbuf);
536       if (!attr)
537         break;
538
539       /* Call the callback */
540       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, attr);
541     }
542     break;
543
544   case SILC_SFTP_EXTENDED_REPLY:
545     {
546       unsigned char *data = NULL;
547
548       SILC_LOG_DEBUG(("Extended reply packet"));
549
550       ret = silc_buffer_unformat(&buf, 
551                                  SILC_STR_UI_INT(&id),
552                                  SILC_STR_UI_XNSTRING(&data, buf.len - 4),
553                                  SILC_STR_END);
554       if (ret < 0)
555         break;
556
557       /* Get request */
558       req = silc_sftp_find_request(sftp, id);
559       if (!req)
560         break;
561
562       /* Call the callback */
563       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, 
564                              data, buf.len - 4);
565     }
566     break;
567
568   default:
569     break;
570   }
571 }
572
573 void silc_sftp_open(SilcSFTP sftp, 
574                     const char *filename,
575                     SilcSFTPFileOperation pflags,
576                     SilcSFTPAttributes attrs,
577                     SilcSFTPHandleCallback callback,
578                     void *context)
579 {
580   SilcSFTPClient client = (SilcSFTPClient)sftp;
581   SilcSFTPRequest req;
582   SilcBuffer attrs_buf;
583   SilcUInt32 len = 0;
584
585   SILC_LOG_DEBUG(("Open request"));
586
587   req = silc_calloc(1, sizeof(*req));
588   req->id = client->id++;
589   req->type = SILC_SFTP_OPEN;
590   req->handle = callback;
591   req->context = context;
592   silc_list_add(client->requests, req);
593
594   attrs_buf = silc_sftp_attr_encode(attrs);
595   len = 4 + 4 + strlen(filename) + 4 + attrs_buf->len;
596
597   silc_sftp_send_packet(client, req->type, len, 
598                         SILC_STR_UI_INT(req->id),
599                         SILC_STR_UI_INT(strlen(filename)),
600                         SILC_STR_UI32_STRING(filename),
601                         SILC_STR_UI_INT(pflags),
602                         SILC_STR_UI_XNSTRING(attrs_buf->data, 
603                                              attrs_buf->len),
604                         SILC_STR_END);
605
606   silc_buffer_free(attrs_buf);
607 }
608
609 void silc_sftp_close(SilcSFTP sftp,
610                      SilcSFTPHandle handle,
611                      SilcSFTPStatusCallback callback,
612                      void *context)
613 {
614   SilcSFTPClient client = (SilcSFTPClient)sftp;
615   SilcSFTPRequest req;
616   SilcUInt32 len = 0;
617   const unsigned char *hdata;
618   SilcUInt32 hdata_len;
619
620   SILC_LOG_DEBUG(("Close request"));
621
622   req = silc_calloc(1, sizeof(*req));
623   req->id = client->id++;
624   req->type = SILC_SFTP_CLOSE;
625   req->status = callback;
626   req->context = context;
627   silc_list_add(client->requests, req);
628
629   silc_sftp_handle_get(handle, &hdata, &hdata_len);
630   len = 4 + 4 + hdata_len;
631
632   silc_sftp_send_packet(client, req->type, len, 
633                         SILC_STR_UI_INT(req->id),
634                         SILC_STR_UI_INT(hdata_len),
635                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
636                         SILC_STR_END);
637 }
638
639 void silc_sftp_read(SilcSFTP sftp,
640                     SilcSFTPHandle handle,
641                     SilcUInt64 offset, 
642                     SilcUInt32 len,
643                     SilcSFTPDataCallback callback,
644                     void *context)
645 {
646   SilcSFTPClient client = (SilcSFTPClient)sftp;
647   SilcSFTPRequest req;
648   SilcUInt32 len2 = 0;
649   const unsigned char *hdata;
650   SilcUInt32 hdata_len;
651
652   SILC_LOG_DEBUG(("Read request"));
653
654   req = silc_calloc(1, sizeof(*req));
655   req->id = client->id++;
656   req->type = SILC_SFTP_READ;
657   req->data = callback;
658   req->context = context;
659   silc_list_add(client->requests, req);
660
661   silc_sftp_handle_get(handle, &hdata, &hdata_len);
662   len2 = 4 + 4 + hdata_len + 8 + 4;
663
664   silc_sftp_send_packet(client, req->type, len2, 
665                         SILC_STR_UI_INT(req->id),
666                         SILC_STR_UI_INT(hdata_len),
667                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
668                         SILC_STR_UI_INT64(offset),
669                         SILC_STR_UI_INT(len),
670                         SILC_STR_END);
671 }
672
673 void silc_sftp_write(SilcSFTP sftp,
674                      SilcSFTPHandle handle,
675                      SilcUInt64 offset,
676                      const unsigned char *data,
677                      SilcUInt32 data_len,
678                      SilcSFTPStatusCallback callback,
679                      void *context)
680 {
681   SilcSFTPClient client = (SilcSFTPClient)sftp;
682   SilcSFTPRequest req;
683   SilcUInt32 len = 0;
684   const unsigned char *hdata;
685   SilcUInt32 hdata_len;
686
687   SILC_LOG_DEBUG(("Write request"));
688
689   req = silc_calloc(1, sizeof(*req));
690   req->id = client->id++;
691   req->type = SILC_SFTP_WRITE;
692   req->status = callback;
693   req->context = context;
694   silc_list_add(client->requests, req);
695
696   silc_sftp_handle_get(handle, &hdata, &hdata_len);
697   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
698
699   silc_sftp_send_packet(client, req->type, len, 
700                         SILC_STR_UI_INT(req->id),
701                         SILC_STR_UI_INT(hdata_len),
702                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
703                         SILC_STR_UI_INT64(offset),
704                         SILC_STR_UI_INT(data_len),
705                         SILC_STR_UI_XNSTRING(data, data_len),
706                         SILC_STR_END);
707 }
708
709 void silc_sftp_remove(SilcSFTP sftp,
710                       const char *filename,
711                       SilcSFTPStatusCallback callback,
712                       void *context)
713 {
714   SilcSFTPClient client = (SilcSFTPClient)sftp;
715   SilcSFTPRequest req;
716   SilcUInt32 len = 0;
717
718   SILC_LOG_DEBUG(("Remove request"));
719
720   req = silc_calloc(1, sizeof(*req));
721   req->id = client->id++;
722   req->type = SILC_SFTP_REMOVE;
723   req->status = callback;
724   req->context = context;
725   silc_list_add(client->requests, req);
726
727   len = 4 + 4 + strlen(filename);
728
729   silc_sftp_send_packet(client, req->type, len, 
730                         SILC_STR_UI_INT(req->id),
731                         SILC_STR_UI_INT(strlen(filename)),
732                         SILC_STR_UI32_STRING(filename),
733                         SILC_STR_END);
734 }
735
736 void silc_sftp_rename(SilcSFTP sftp,
737                       const char *oldname,
738                       const char *newname,
739                       SilcSFTPStatusCallback callback,
740                       void *context)
741 {
742   SilcSFTPClient client = (SilcSFTPClient)sftp;
743   SilcSFTPRequest req;
744   SilcUInt32 len = 0;
745
746   SILC_LOG_DEBUG(("Rename request"));
747
748   req = silc_calloc(1, sizeof(*req));
749   req->id = client->id++;
750   req->type = SILC_SFTP_RENAME;
751   req->status = callback;
752   req->context = context;
753   silc_list_add(client->requests, req);
754
755   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
756
757   silc_sftp_send_packet(client, req->type, len, 
758                         SILC_STR_UI_INT(req->id),
759                         SILC_STR_UI_INT(strlen(oldname)),
760                         SILC_STR_UI32_STRING(oldname),
761                         SILC_STR_UI_INT(strlen(newname)),
762                         SILC_STR_UI32_STRING(newname),
763                         SILC_STR_END);
764 }
765
766 void silc_sftp_mkdir(SilcSFTP sftp,
767                      const char *path,
768                      SilcSFTPAttributes attrs,
769                      SilcSFTPStatusCallback callback,
770                      void *context)
771 {
772   SilcSFTPClient client = (SilcSFTPClient)sftp;
773   SilcSFTPRequest req;
774   SilcUInt32 len = 0;
775   SilcBuffer attrs_buf;
776
777   SILC_LOG_DEBUG(("Mkdir request"));
778
779   req = silc_calloc(1, sizeof(*req));
780   req->id = client->id++;
781   req->type = SILC_SFTP_MKDIR;
782   req->status = callback;
783   req->context = context;
784   silc_list_add(client->requests, req);
785
786   attrs_buf = silc_sftp_attr_encode(attrs);
787   len = 4 + 4 + strlen(path) + attrs_buf->len;
788
789   silc_sftp_send_packet(client, req->type, len, 
790                         SILC_STR_UI_INT(req->id),
791                         SILC_STR_UI_INT(strlen(path)),
792                         SILC_STR_UI32_STRING(path),
793                         SILC_STR_UI_XNSTRING(attrs_buf->data,
794                                              attrs_buf->len),
795                         SILC_STR_END);
796
797   silc_buffer_free(attrs_buf);
798 }
799
800 void silc_sftp_rmdir(SilcSFTP sftp,
801                      const char *path,
802                      SilcSFTPStatusCallback callback,
803                      void *context)
804 {
805   SilcSFTPClient client = (SilcSFTPClient)sftp;
806   SilcSFTPRequest req;
807   SilcUInt32 len = 0;
808
809   SILC_LOG_DEBUG(("Rmdir request"));
810
811   req = silc_calloc(1, sizeof(*req));
812   req->id = client->id++;
813   req->type = SILC_SFTP_RMDIR;
814   req->status = callback;
815   req->context = context;
816   silc_list_add(client->requests, req);
817
818   len = 4 + 4 + strlen(path);
819
820   silc_sftp_send_packet(client, req->type, len, 
821                         SILC_STR_UI_INT(req->id),
822                         SILC_STR_UI_INT(strlen(path)),
823                         SILC_STR_UI32_STRING(path),
824                         SILC_STR_END);
825 }
826
827 void silc_sftp_opendir(SilcSFTP sftp,
828                        const char *path,
829                        SilcSFTPHandleCallback callback,
830                        void *context)
831 {
832   SilcSFTPClient client = (SilcSFTPClient)sftp;
833   SilcSFTPRequest req;
834   SilcUInt32 len = 0;
835
836   SILC_LOG_DEBUG(("Opendir request"));
837
838   req = silc_calloc(1, sizeof(*req));
839   req->id = client->id++;
840   req->type = SILC_SFTP_OPENDIR;
841   req->handle = callback;
842   req->context = context;
843   silc_list_add(client->requests, req);
844
845   len = 4 + 4 + strlen(path);
846
847   silc_sftp_send_packet(client, req->type, len, 
848                         SILC_STR_UI_INT(req->id),
849                         SILC_STR_UI_INT(strlen(path)),
850                         SILC_STR_UI32_STRING(path),
851                         SILC_STR_END);
852 }
853
854 void silc_sftp_readdir(SilcSFTP sftp,
855                        SilcSFTPHandle handle,
856                        SilcSFTPNameCallback callback,
857                        void *context)
858 {
859   SilcSFTPClient client = (SilcSFTPClient)sftp;
860   SilcSFTPRequest req;
861   SilcUInt32 len = 0;
862   const unsigned char *hdata;
863   SilcUInt32 hdata_len;
864
865   SILC_LOG_DEBUG(("Readdir request"));
866
867   req = silc_calloc(1, sizeof(*req));
868   req->id = client->id++;
869   req->type = SILC_SFTP_READDIR;
870   req->name = callback;
871   req->context = context;
872   silc_list_add(client->requests, req);
873
874   silc_sftp_handle_get(handle, &hdata, &hdata_len);
875   len = 4 + 4 + hdata_len;
876
877   silc_sftp_send_packet(client, req->type, len, 
878                         SILC_STR_UI_INT(req->id),
879                         SILC_STR_UI_INT(hdata_len),
880                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
881                         SILC_STR_END);
882 }
883
884 void silc_sftp_stat(SilcSFTP sftp,
885                     const char *path,
886                     SilcSFTPAttrCallback callback,
887                     void *context)
888 {
889   SilcSFTPClient client = (SilcSFTPClient)sftp;
890   SilcSFTPRequest req;
891   SilcUInt32 len = 0;
892
893   SILC_LOG_DEBUG(("Stat request"));
894
895   req = silc_calloc(1, sizeof(*req));
896   req->id = client->id++;
897   req->type = SILC_SFTP_STAT;
898   req->attr = callback;
899   req->context = context;
900   silc_list_add(client->requests, req);
901
902   len = 4 + 4 + strlen(path);
903
904   silc_sftp_send_packet(client, req->type, len, 
905                         SILC_STR_UI_INT(req->id),
906                         SILC_STR_UI_INT(strlen(path)),
907                         SILC_STR_UI32_STRING(path),
908                         SILC_STR_END);
909 }
910
911 void silc_sftp_lstat(SilcSFTP sftp,
912                      const char *path,
913                      SilcSFTPAttrCallback callback,
914                      void *context)
915 {
916   SilcSFTPClient client = (SilcSFTPClient)sftp;
917   SilcSFTPRequest req;
918   SilcUInt32 len = 0;
919
920   SILC_LOG_DEBUG(("Lstat request"));
921
922   req = silc_calloc(1, sizeof(*req));
923   req->id = client->id++;
924   req->type = SILC_SFTP_LSTAT;
925   req->attr = callback;
926   req->context = context;
927   silc_list_add(client->requests, req);
928
929   len = 4 + 4 + strlen(path);
930
931   silc_sftp_send_packet(client, req->type, len, 
932                         SILC_STR_UI_INT(req->id),
933                         SILC_STR_UI_INT(strlen(path)),
934                         SILC_STR_UI32_STRING(path),
935                         SILC_STR_END);
936 }
937
938 void silc_sftp_fstat(SilcSFTP sftp,
939                      SilcSFTPHandle handle,
940                      SilcSFTPAttrCallback callback,
941                      void *context)
942 {
943   SilcSFTPClient client = (SilcSFTPClient)sftp;
944   SilcSFTPRequest req;
945   SilcUInt32 len = 0;
946   const unsigned char *hdata;
947   SilcUInt32 hdata_len;
948
949   SILC_LOG_DEBUG(("Fstat request"));
950
951   req = silc_calloc(1, sizeof(*req));
952   req->id = client->id++;
953   req->type = SILC_SFTP_FSTAT;
954   req->attr = callback;
955   req->context = context;
956   silc_list_add(client->requests, req);
957
958   silc_sftp_handle_get(handle, &hdata, &hdata_len);
959   len = 4 + 4 + hdata_len;
960
961   silc_sftp_send_packet(client, req->type, len, 
962                         SILC_STR_UI_INT(req->id),
963                         SILC_STR_UI_INT(hdata_len),
964                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
965                         SILC_STR_END);
966 }
967
968 void silc_sftp_setstat(SilcSFTP sftp,
969                        const char *path,
970                        SilcSFTPAttributes attrs,
971                        SilcSFTPStatusCallback callback,
972                        void *context)
973 {
974   SilcSFTPClient client = (SilcSFTPClient)sftp;
975   SilcSFTPRequest req;
976   SilcUInt32 len = 0;
977   SilcBuffer attrs_buf;
978
979   SILC_LOG_DEBUG(("Setstat request"));
980
981   req = silc_calloc(1, sizeof(*req));
982   req->id = client->id++;
983   req->type = SILC_SFTP_SETSTAT;
984   req->status = callback;
985   req->context = context;
986   silc_list_add(client->requests, req);
987
988   attrs_buf = silc_sftp_attr_encode(attrs);
989   len = 4 + 4 + strlen(path) + attrs_buf->len;
990
991   silc_sftp_send_packet(client, req->type, len, 
992                         SILC_STR_UI_INT(req->id),
993                         SILC_STR_UI_INT(strlen(path)),
994                         SILC_STR_UI32_STRING(path),
995                         SILC_STR_UI_XNSTRING(attrs_buf->data,
996                                              attrs_buf->len),
997                         SILC_STR_END);
998
999   silc_buffer_free(attrs_buf);
1000 }
1001
1002 void silc_sftp_fsetstat(SilcSFTP sftp,
1003                         SilcSFTPHandle handle,
1004                         SilcSFTPAttributes attrs,
1005                         SilcSFTPStatusCallback callback,
1006                         void *context)
1007 {
1008   SilcSFTPClient client = (SilcSFTPClient)sftp;
1009   SilcSFTPRequest req;
1010   SilcUInt32 len = 0;
1011   SilcBuffer attrs_buf;
1012   const unsigned char *hdata;
1013   SilcUInt32 hdata_len;
1014
1015   SILC_LOG_DEBUG(("Fsetstat request"));
1016
1017   req = silc_calloc(1, sizeof(*req));
1018   req->id = client->id++;
1019   req->type = SILC_SFTP_FSETSTAT;
1020   req->status = callback;
1021   req->context = context;
1022   silc_list_add(client->requests, req);
1023
1024   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1025   attrs_buf = silc_sftp_attr_encode(attrs);
1026   len = 4 + 4 + hdata_len + attrs_buf->len;
1027
1028   silc_sftp_send_packet(client, req->type, len, 
1029                         SILC_STR_UI_INT(req->id),
1030                         SILC_STR_UI_INT(hdata_len),
1031                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1032                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1033                                              attrs_buf->len),
1034                         SILC_STR_END);
1035
1036   silc_buffer_free(attrs_buf);
1037 }
1038
1039 void silc_sftp_readlink(SilcSFTP sftp,
1040                         const char *path,
1041                         SilcSFTPNameCallback callback,
1042                         void *context)
1043 {
1044   SilcSFTPClient client = (SilcSFTPClient)sftp;
1045   SilcSFTPRequest req;
1046   SilcUInt32 len = 0;
1047
1048   SILC_LOG_DEBUG(("Readlink request"));
1049
1050   req = silc_calloc(1, sizeof(*req));
1051   req->id = client->id++;
1052   req->type = SILC_SFTP_READLINK;
1053   req->name = callback;
1054   req->context = context;
1055   silc_list_add(client->requests, req);
1056
1057   len = 4 + 4 + strlen(path);
1058
1059   silc_sftp_send_packet(client, req->type, len, 
1060                         SILC_STR_UI_INT(req->id),
1061                         SILC_STR_UI_INT(strlen(path)),
1062                         SILC_STR_UI32_STRING(path),
1063                         SILC_STR_END);
1064 }
1065
1066 void silc_sftp_symlink(SilcSFTP sftp,
1067                        const char *linkpath,
1068                        const char *targetpath,
1069                        SilcSFTPStatusCallback callback,
1070                        void *context)
1071 {
1072   SilcSFTPClient client = (SilcSFTPClient)sftp;
1073   SilcSFTPRequest req;
1074   SilcUInt32 len = 0;
1075
1076   SILC_LOG_DEBUG(("Symlink request"));
1077
1078   req = silc_calloc(1, sizeof(*req));
1079   req->id = client->id++;
1080   req->type = SILC_SFTP_SYMLINK;
1081   req->status = callback;
1082   req->context = context;
1083   silc_list_add(client->requests, req);
1084
1085   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1086
1087   silc_sftp_send_packet(client, req->type, len, 
1088                         SILC_STR_UI_INT(req->id),
1089                         SILC_STR_UI_INT(strlen(linkpath)),
1090                         SILC_STR_UI32_STRING(linkpath),
1091                         SILC_STR_UI_INT(strlen(targetpath)),
1092                         SILC_STR_UI32_STRING(targetpath),
1093                         SILC_STR_END);
1094 }
1095
1096 void silc_sftp_realpath(SilcSFTP sftp,
1097                         const char *path,
1098                         SilcSFTPNameCallback callback,
1099                         void *context)
1100 {
1101   SilcSFTPClient client = (SilcSFTPClient)sftp;
1102   SilcSFTPRequest req;
1103   SilcUInt32 len = 0;
1104
1105   SILC_LOG_DEBUG(("Realpath request"));
1106
1107   req = silc_calloc(1, sizeof(*req));
1108   req->id = client->id++;
1109   req->type = SILC_SFTP_REALPATH;
1110   req->name = callback;
1111   req->context = context;
1112   silc_list_add(client->requests, req);
1113
1114   len = 4 + 4 + strlen(path);
1115
1116   silc_sftp_send_packet(client, req->type, len, 
1117                         SILC_STR_UI_INT(req->id),
1118                         SILC_STR_UI_INT(strlen(path)),
1119                         SILC_STR_UI32_STRING(path),
1120                         SILC_STR_END);
1121 }
1122
1123 void silc_sftp_extended(SilcSFTP sftp,
1124                         const char *request,
1125                         const unsigned char *data,
1126                         SilcUInt32 data_len,
1127                         SilcSFTPExtendedCallback callback,
1128                         void *context)
1129 {
1130   SilcSFTPClient client = (SilcSFTPClient)sftp;
1131   SilcSFTPRequest req;
1132   SilcUInt32 len = 0;
1133
1134   SILC_LOG_DEBUG(("Extended request"));
1135
1136   req = silc_calloc(1, sizeof(*req));
1137   req->id = client->id++;
1138   req->type = SILC_SFTP_WRITE;
1139   req->extended = callback;
1140   req->context = context;
1141   silc_list_add(client->requests, req);
1142
1143   len = 4 + 4 + strlen(request) + data_len;
1144
1145   silc_sftp_send_packet(client, req->type, len, 
1146                         SILC_STR_UI_INT(req->id),
1147                         SILC_STR_UI_INT(strlen(request)),
1148                         SILC_STR_UI32_STRING(request),
1149                         SILC_STR_UI_XNSTRING(data, data_len),
1150                         SILC_STR_END);
1151 }