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