Integer type name change.
[silc.git] / lib / silcsftp / sftp_server.c
1 /*
2
3   sftp_server.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 "silcsftp_fs.h"
24 #include "sftp_util.h"
25
26 /* SFTP Server context */
27 typedef struct {
28   SilcSocketConnection sock;
29   SilcSFTPSendPacketCallback send_packet;
30   void *send_context;
31   SilcSFTPMonitors monitors;
32   SilcSFTPMonitor monitor;
33   void *monitor_context;
34   SilcSFTPFilesystem fs;
35   SilcBuffer packet;
36 } *SilcSFTPServer;
37
38 /* General routine to send SFTP packet to the SFTP client. */
39
40 static void silc_sftp_send_packet(SilcSFTPServer sftp,
41                                   SilcSFTPPacket type, 
42                                   SilcUInt32 len, ...)
43 {
44   SilcBuffer tmp;
45   va_list vp;
46
47   va_start(vp, len);
48   tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
49   va_end(vp);
50   if (!tmp)
51     return;
52   sftp->packet = tmp;
53
54   SILC_LOG_HEXDUMP(("SFTP packet to client"), sftp->packet->data, 
55                    sftp->packet->len);
56
57   /* Send the packet */
58   (*sftp->send_packet)(sftp->sock, sftp->packet, sftp->send_context);
59
60   /* Clear packet */
61   sftp->packet->data = sftp->packet->tail = sftp->packet->head;
62   sftp->packet->len = 0;
63 }
64
65 /* Sends error to the client */
66
67 static void silc_sftp_send_error(SilcSFTPServer sftp,
68                                  SilcSFTPStatus status,
69                                  SilcUInt32 id)
70 {
71   SILC_LOG_DEBUG(("Send error %d", status));
72
73   silc_sftp_send_packet(sftp, SILC_SFTP_STATUS, 16,
74                         SILC_STR_UI_INT(id),
75                         SILC_STR_UI_INT(status),
76                         SILC_STR_UI_INT(0),      /* Error */
77                         SILC_STR_UI_INT(0),      /* Language tag */
78                         SILC_STR_END);
79 }
80
81 /* Status callback */
82
83 static void silc_sftp_server_status(SilcSFTP sftp,
84                                     SilcSFTPStatus status,
85                                     const char *message,
86                                     const char *language_tag,
87                                     void *context)
88 {
89   SilcSFTPServer server = (SilcSFTPServer)sftp;
90   SilcUInt32 id = (SilcUInt32)context;
91   int mlen, llen;
92
93   SILC_LOG_DEBUG(("Status callback"));
94   SILC_LOG_DEBUG(("Request ID: %d", id));
95   
96   if (!message)
97     message = "";
98   if (!language_tag)
99     language_tag = "";
100   mlen = strlen(message);
101   llen = strlen(language_tag);
102
103   silc_sftp_send_packet(server, SILC_SFTP_STATUS, 16 + mlen + llen,
104                         SILC_STR_UI_INT(id),
105                         SILC_STR_UI_INT(status),
106                         SILC_STR_UI_INT(mlen),
107                         SILC_STR_UI32_STRING(message),
108                         SILC_STR_UI_INT(llen),
109                         SILC_STR_UI32_STRING(language_tag),
110                         SILC_STR_END);
111 }
112
113 /* Handle callback */
114
115 static void silc_sftp_server_handle(SilcSFTP sftp,
116                                     SilcSFTPStatus status,
117                                     SilcSFTPHandle handle,
118                                     void *context)
119 {
120   SilcSFTPServer server = (SilcSFTPServer)sftp;
121   SilcUInt32 id = (SilcUInt32)context;
122   unsigned char *hdata;
123   SilcUInt32 hdata_len;
124
125   SILC_LOG_DEBUG(("Handle callback"));
126   SILC_LOG_DEBUG(("Request ID: %d", id));
127
128   if (status != SILC_SFTP_STATUS_OK) {
129     silc_sftp_send_error(server, status, id);
130     return;
131   }
132
133   hdata = server->fs->fs->sftp_encode_handle(server->fs->fs_context, sftp,
134                                              handle, &hdata_len);
135   if (!hdata) {
136     silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
137     return;
138   }
139
140   silc_sftp_send_packet(server, SILC_SFTP_HANDLE, 8 + hdata_len,
141                         SILC_STR_UI_INT(id),
142                         SILC_STR_UI_INT(hdata_len),
143                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
144                         SILC_STR_END);
145 }
146
147 /* Data callback */
148
149 static void silc_sftp_server_data(SilcSFTP sftp,
150                                   SilcSFTPStatus status,
151                                   const unsigned char *data,
152                                   SilcUInt32 data_len,
153                                   void *context)
154 {
155   SilcSFTPServer server = (SilcSFTPServer)sftp;
156   SilcUInt32 id = (SilcUInt32)context;
157
158   SILC_LOG_DEBUG(("Data callback"));
159   SILC_LOG_DEBUG(("Request ID: %d", id));
160
161   if (status != SILC_SFTP_STATUS_OK) {
162     silc_sftp_send_error(server, status, id);
163     return;
164   }
165
166   silc_sftp_send_packet(server, SILC_SFTP_DATA, 8 + data_len,
167                         SILC_STR_UI_INT(id),
168                         SILC_STR_UI_INT(data_len),
169                         SILC_STR_UI_XNSTRING(data, data_len),
170                         SILC_STR_END);
171 }
172
173 /* Name callback */
174
175 static void silc_sftp_server_name(SilcSFTP sftp,
176                                   SilcSFTPStatus status,
177                                   const SilcSFTPName name,
178                                   void *context)
179 {
180   SilcSFTPServer server = (SilcSFTPServer)sftp;
181   SilcUInt32 id = (SilcUInt32)context;
182   SilcBuffer namebuf;
183
184   SILC_LOG_DEBUG(("Name callback"));
185   SILC_LOG_DEBUG(("Request ID: %d", id));
186
187   if (status != SILC_SFTP_STATUS_OK) {
188     silc_sftp_send_error(server, status, id);
189     return;
190   }
191
192   namebuf = silc_sftp_name_encode(name);
193   if (!namebuf) {
194     silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
195     return;
196   }
197
198   silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + namebuf->len,
199                         SILC_STR_UI_INT(id),
200                         SILC_STR_UI_XNSTRING(namebuf->data, namebuf->len),
201                         SILC_STR_END);
202 }
203
204 /* Attributes callback */
205
206 static void silc_sftp_server_attr(SilcSFTP sftp,
207                                   SilcSFTPStatus status,
208                                   const SilcSFTPAttributes attrs,
209                                   void *context)
210 {
211   SilcSFTPServer server = (SilcSFTPServer)sftp;
212   SilcUInt32 id = (SilcUInt32)context;
213   SilcBuffer attr_buf;
214
215   SILC_LOG_DEBUG(("Attr callback"));
216   SILC_LOG_DEBUG(("Request ID: %d", id));
217
218   if (status != SILC_SFTP_STATUS_OK) {
219     silc_sftp_send_error(server, status, id);
220     return;
221   }
222
223   attr_buf = silc_sftp_attr_encode(attrs);
224
225   silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
226                         SILC_STR_UI_INT(id),
227                         SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
228                         SILC_STR_END);
229
230   silc_buffer_free(attr_buf);
231 }
232
233 /* Extended callback */
234
235 static void silc_sftp_server_extended(SilcSFTP sftp,
236                                       SilcSFTPStatus status,
237                                       const unsigned char *data,
238                                       SilcUInt32 data_len,
239                                       void *context)
240 {
241   SilcSFTPServer server = (SilcSFTPServer)sftp;
242   SilcUInt32 id = (SilcUInt32)context;
243
244   SILC_LOG_DEBUG(("Extended callback"));
245   SILC_LOG_DEBUG(("Request ID: %d", id));
246
247   if (status != SILC_SFTP_STATUS_OK) {
248     silc_sftp_send_error(server, status, id);
249     return;
250   }
251
252   silc_sftp_send_packet(server, SILC_SFTP_EXTENDED, 4 + data_len,
253                         SILC_STR_UI_INT(id),
254                         SILC_STR_UI_XNSTRING(data, data_len),
255                         SILC_STR_END);
256 }
257
258 /* Starts SFTP server by associating the socket connection `sock' to the
259    created SFTP server context.  This function returns the allocated
260    SFTP client context or NULL on error. The `send_packet' is called
261    by the library when it needs to send a packet. The `fs' is the
262    structure containing filesystem access callbacks. */
263
264 SilcSFTP silc_sftp_server_start(SilcSocketConnection sock,
265                                 SilcSFTPSendPacketCallback send_packet,
266                                 void *send_context,
267                                 SilcSFTPFilesystem fs)
268 {
269   SilcSFTPServer server;
270
271   server = silc_calloc(1, sizeof(*server));
272   server->sock = sock;
273   server->send_packet = send_packet;
274   server->send_context = send_context;
275   server->fs = fs;
276
277   SILC_LOG_DEBUG(("Starting SFTP server %p", server));
278
279   return (SilcSFTP)server;
280 }
281
282 /* Shutdown's the SFTP server.  The caller is responsible of closing
283    the associated socket connection.  The SFTP context is freed and is
284    invalid after this function returns. */
285
286 void silc_sftp_server_shutdown(SilcSFTP sftp)
287 {
288   SilcSFTPServer server = (SilcSFTPServer)sftp;
289
290   SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
291
292   if (server->packet)
293     silc_buffer_free(server->packet);
294   silc_free(server);
295 }
296
297 /* Sets monitor callback */
298
299 void silc_sftp_server_set_monitor(SilcSFTP sftp,
300                                   SilcSFTPMonitors monitors,
301                                   SilcSFTPMonitor monitor, 
302                                   void *context)
303 {
304   SilcSFTPServer server = (SilcSFTPServer)sftp;
305   server->monitors = monitors;
306   server->monitor = monitor;
307   server->monitor_context = context;
308 }
309
310 /* Function that is called to process the incmoing SFTP packet. */
311 /* XXX Some day this will go away and we have automatic receive callbacks
312    for SilcSocketConnection API or SilcPacketContext API. */
313
314 void silc_sftp_server_receive_process(SilcSFTP sftp,
315                                       SilcSocketConnection sock,
316                                       SilcPacketContext *packet)
317 {
318   SilcSFTPServer server = (SilcSFTPServer)sftp;
319   SilcSFTPPacket type;
320   char *filename = NULL, *path = NULL;
321   const unsigned char *payload = NULL;
322   SilcUInt32 payload_len;
323   int ret;
324   SilcBufferStruct buf;
325   SilcUInt32 id;
326   SilcSFTPAttributes attrs;
327   SilcSFTPHandle handle;
328   SilcSFTPMonitorDataStruct mdata;
329
330   SILC_LOG_DEBUG(("Start"));
331
332   /* Parse the packet */
333   type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload, 
334                                  &payload_len);
335   if (!type)
336     return;
337
338   silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
339
340   memset(&mdata, 0, sizeof(mdata));
341
342   switch (type) {
343   case SILC_SFTP_INIT:
344     {
345       SilcSFTPVersion version;
346
347       SILC_LOG_DEBUG(("Init request"));
348
349       ret = silc_buffer_unformat(&buf,
350                                  SILC_STR_UI_INT(&version),
351                                  SILC_STR_END);
352       if (ret < 0)
353         break;
354
355       /* Call monitor */
356       if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) {
357         mdata.version = version;
358         (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata,
359                            server->monitor_context);
360       }
361
362       silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
363                             SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
364                             SILC_STR_END);
365     }
366     break;
367
368   case SILC_SFTP_OPEN:
369     {
370       SilcSFTPFileOperation pflags;
371       unsigned char *attr_buf;
372       SilcUInt32 attr_len = 0;
373       SilcBufferStruct tmpbuf;
374
375       SILC_LOG_DEBUG(("Open request"));
376
377       ret = silc_buffer_unformat(&buf,
378                                  SILC_STR_UI_INT(&id),
379                                  SILC_STR_UI32_STRING_ALLOC(&filename),
380                                  SILC_STR_UI_INT(&pflags),
381                                  SILC_STR_UI32_NSTRING(&attr_buf, 
382                                                        &attr_len),
383                                  SILC_STR_END);
384       if (ret < 0)
385         goto failure;
386
387       if (attr_len) {
388         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
389         attrs = silc_sftp_attr_decode(&tmpbuf);
390       } else {
391         attrs = silc_calloc(1, sizeof(*attrs));
392       }
393
394       /* Call monitor */
395       if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) {
396         mdata.name = filename;
397         mdata.pflags = pflags;
398         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata,
399                            server->monitor_context);
400       }
401
402       /* Open operation */
403       server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags,
404                                 attrs, silc_sftp_server_handle, (void *)id);
405
406       silc_free(filename);
407       silc_sftp_attr_free(attrs);
408     }
409     break;
410
411   case SILC_SFTP_CLOSE:
412     {
413       unsigned char *hdata;
414       SilcUInt32 hdata_len;
415
416       SILC_LOG_DEBUG(("Close request"));
417
418       ret = silc_buffer_unformat(&buf,
419                                  SILC_STR_UI_INT(&id),
420                                  SILC_STR_UI32_NSTRING(&hdata, 
421                                                        &hdata_len),
422                                  SILC_STR_END);
423       if (ret < 0)
424         goto failure;
425
426       /* Get the handle */
427       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
428                                                (const unsigned char *)hdata,
429                                                hdata_len);
430       if (!handle) {
431         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
432         break;
433       }
434
435       /* Call monitor */
436       if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) {
437         (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata,
438                            server->monitor_context);
439       }
440
441       /* Close operation */
442       server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
443                                  silc_sftp_server_status, (void *)id);
444     }
445     break;
446
447   case SILC_SFTP_READ:
448     {
449       unsigned char *hdata;
450       SilcUInt32 hdata_len;
451       SilcUInt64 offset;
452       SilcUInt32 len;
453
454       SILC_LOG_DEBUG(("Read request"));
455
456       ret = silc_buffer_unformat(&buf,
457                                  SILC_STR_UI_INT(&id),
458                                  SILC_STR_UI32_NSTRING(&hdata, 
459                                                        &hdata_len),
460                                  SILC_STR_UI_INT64(&offset),
461                                  SILC_STR_UI_INT(&len),
462                                  SILC_STR_END);
463       if (ret < 0)
464         goto failure;
465
466       /* Get the handle */
467       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
468                                                (const unsigned char *)hdata,
469                                                hdata_len);
470       if (!handle) {
471         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
472         break;
473       }
474
475       /* Call monitor */
476       if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
477         mdata.offset = offset;
478         mdata.data_len = len;
479         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
480                            server->monitor_context);
481       }
482
483       /* Read operation */
484       server->fs->fs->sftp_read(server->fs->fs_context, sftp, 
485                                 handle, offset, len,
486                                 silc_sftp_server_data, (void *)id);
487     }
488     break;
489
490   case SILC_SFTP_WRITE:
491     {
492       unsigned char *hdata;
493       SilcUInt32 hdata_len;
494       SilcUInt64 offset;
495       unsigned char *data;
496       SilcUInt32 data_len;
497
498       SILC_LOG_DEBUG(("Read request"));
499
500       ret = silc_buffer_unformat(&buf,
501                                  SILC_STR_UI_INT(&id),
502                                  SILC_STR_UI32_NSTRING(&hdata, 
503                                                        &hdata_len),
504                                  SILC_STR_UI_INT64(&offset),
505                                  SILC_STR_UI32_NSTRING(&data, 
506                                                        &data_len),
507                                  SILC_STR_END);
508       if (ret < 0)
509         goto failure;
510
511       /* Get the handle */
512       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
513                                                (const unsigned char *)hdata,
514                                                hdata_len);
515       if (!handle) {
516         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
517         break;
518       }
519
520       /* Call monitor */
521       if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
522         mdata.offset = offset;
523         mdata.data_len = data_len;
524         (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
525                            server->monitor_context);
526       }
527
528       /* Write operation */
529       server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, 
530                                  (const unsigned char *)data, data_len,
531                                  silc_sftp_server_status, (void *)id);
532     }
533     break;
534
535   case SILC_SFTP_REMOVE:
536     {
537       SILC_LOG_DEBUG(("Remove request"));
538
539       ret = silc_buffer_unformat(&buf,
540                                  SILC_STR_UI_INT(&id),
541                                  SILC_STR_UI32_STRING_ALLOC(&filename),
542                                  SILC_STR_END);
543       if (ret < 0)
544         goto failure;
545
546       /* Call monitor */
547       if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) {
548         mdata.name = filename;
549         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata,
550                            server->monitor_context);
551       }
552
553       /* Remove operation */
554       server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
555                                   silc_sftp_server_status, (void *)id);
556
557       silc_free(filename);
558     }
559     break;
560
561   case SILC_SFTP_RENAME:
562     {
563       char *newname = NULL;
564
565       SILC_LOG_DEBUG(("Rename request"));
566
567       ret = silc_buffer_unformat(&buf,
568                                  SILC_STR_UI_INT(&id),
569                                  SILC_STR_UI32_STRING_ALLOC(&filename),
570                                  SILC_STR_UI32_STRING_ALLOC(&newname),
571                                  SILC_STR_END);
572       if (ret < 0)
573         goto failure;
574
575       /* Call monitor */
576       if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) {
577         mdata.name = filename;
578         mdata.name2 = newname;
579         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata,
580                            server->monitor_context);
581       }
582
583       /* Rename operation */
584       server->fs->fs->sftp_rename(server->fs->fs_context, sftp, 
585                                   filename, newname,
586                                   silc_sftp_server_status, (void *)id);
587
588       silc_free(filename);
589       silc_free(newname);
590     }
591     break;
592
593   case SILC_SFTP_MKDIR:
594     {
595       unsigned char *attr_buf;
596       SilcUInt32 attr_len = 0;
597       SilcBufferStruct tmpbuf;
598
599       SILC_LOG_DEBUG(("Mkdir request"));
600
601       ret = silc_buffer_unformat(&buf,
602                                  SILC_STR_UI_INT(&id),
603                                  SILC_STR_UI32_STRING_ALLOC(&path),
604                                  SILC_STR_UI32_NSTRING(&attr_buf,
605                                                        &attr_len),
606                                  SILC_STR_END);
607       if (ret < 0)
608         goto failure;
609
610       if (attr_len) {
611         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
612         attrs = silc_sftp_attr_decode(&tmpbuf);
613       } else {
614         attrs = silc_calloc(1, sizeof(*attrs));
615       }
616
617       /* Call monitor */
618       if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) {
619         mdata.name = path;
620         (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata,
621                            server->monitor_context);
622       }
623
624       /* Mkdir operation */
625       server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
626                                  silc_sftp_server_status, (void *)id);
627
628       silc_sftp_attr_free(attrs);
629       silc_free(path);
630     }
631     break;
632
633   case SILC_SFTP_RMDIR:
634     {
635       SILC_LOG_DEBUG(("Rmdir request"));
636
637       ret = silc_buffer_unformat(&buf,
638                                  SILC_STR_UI_INT(&id),
639                                  SILC_STR_UI32_STRING_ALLOC(&path),
640                                  SILC_STR_END);
641       if (ret < 0)
642         goto failure;
643
644       /* Call monitor */
645       if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) {
646         mdata.name = path;
647         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata,
648                            server->monitor_context);
649       }
650
651       /* Rmdir operation */
652       server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
653                                  silc_sftp_server_status, (void *)id);
654
655       silc_free(path);
656     }
657     break;
658
659   case SILC_SFTP_OPENDIR:
660     {
661       SILC_LOG_DEBUG(("Opendir request"));
662
663       ret = silc_buffer_unformat(&buf,
664                                  SILC_STR_UI_INT(&id),
665                                  SILC_STR_UI32_STRING_ALLOC(&path),
666                                  SILC_STR_END);
667       if (ret < 0)
668         goto failure;
669
670       /* Call monitor */
671       if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) {
672         mdata.name = path;
673         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata,
674                            server->monitor_context);
675       }
676
677       /* Opendir operation */
678       server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
679                                    silc_sftp_server_handle, (void *)id);
680
681       silc_free(path);
682     }
683     break;
684
685   case SILC_SFTP_READDIR:
686     {
687       unsigned char *hdata;
688       SilcUInt32 hdata_len;
689
690       SILC_LOG_DEBUG(("Readdir request"));
691
692       ret = silc_buffer_unformat(&buf,
693                                  SILC_STR_UI_INT(&id),
694                                  SILC_STR_UI32_NSTRING(&hdata, 
695                                                        &hdata_len),
696                                  SILC_STR_END);
697       if (ret < 0)
698         goto failure;
699
700       /* Get the handle */
701       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
702                                                (const unsigned char *)hdata,
703                                                hdata_len);
704       if (!handle) {
705         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
706         break;
707       }
708
709       /* Call monitor */
710       if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) {
711         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata,
712                            server->monitor_context);
713       }
714
715       /* Readdir operation */
716       server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
717                                    silc_sftp_server_name, (void *)id);
718     }
719     break;
720
721   case SILC_SFTP_STAT:
722     {
723       SILC_LOG_DEBUG(("Stat request"));
724
725       ret = silc_buffer_unformat(&buf,
726                                  SILC_STR_UI_INT(&id),
727                                  SILC_STR_UI32_STRING_ALLOC(&path),
728                                  SILC_STR_END);
729       if (ret < 0)
730         goto failure;
731
732       /* Call monitor */
733       if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) {
734         mdata.name = path;
735         (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata,
736                            server->monitor_context);
737       }
738
739       /* Stat operation */
740       server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
741                                 silc_sftp_server_attr, (void *)id);
742
743       silc_free(path);
744     }
745     break;
746
747   case SILC_SFTP_LSTAT:
748     {
749       SILC_LOG_DEBUG(("Lstat request"));
750
751       ret = silc_buffer_unformat(&buf,
752                                  SILC_STR_UI_INT(&id),
753                                  SILC_STR_UI32_STRING_ALLOC(&path),
754                                  SILC_STR_END);
755       if (ret < 0)
756         goto failure;
757
758       /* Call monitor */
759       if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) {
760         mdata.name = path;
761         (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata,
762                            server->monitor_context);
763       }
764
765       /* Lstat operation */
766       server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
767                                  silc_sftp_server_attr, (void *)id);
768
769       silc_free(path);
770     }
771     break;
772
773   case SILC_SFTP_FSTAT:
774     {
775       unsigned char *hdata;
776       SilcUInt32 hdata_len;
777
778       SILC_LOG_DEBUG(("Fstat request"));
779
780       ret = silc_buffer_unformat(&buf,
781                                  SILC_STR_UI_INT(&id),
782                                  SILC_STR_UI32_NSTRING(&hdata, 
783                                                        &hdata_len),
784                                  SILC_STR_END);
785       if (ret < 0)
786         goto failure;
787
788       /* Get the handle */
789       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
790                                                (const unsigned char *)hdata,
791                                                hdata_len);
792       if (!handle) {
793         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
794         break;
795       }
796
797       /* Call monitor */
798       if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) {
799         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata,
800                            server->monitor_context);
801       }
802
803       /* Fstat operation */
804       server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
805                                  silc_sftp_server_attr, (void *)id);
806     }
807     break;
808
809   case SILC_SFTP_SETSTAT:
810     {
811       unsigned char *attr_buf;
812       SilcUInt32 attr_len = 0;
813       SilcBufferStruct tmpbuf;
814
815       SILC_LOG_DEBUG(("Setstat request"));
816
817       ret = silc_buffer_unformat(&buf,
818                                  SILC_STR_UI_INT(&id),
819                                  SILC_STR_UI32_STRING_ALLOC(&path),
820                                  SILC_STR_UI32_NSTRING(&attr_buf,
821                                                        &attr_len),
822                                  SILC_STR_END);
823       if (ret < 0)
824         goto failure;
825
826       if (attr_len) {
827         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
828         attrs = silc_sftp_attr_decode(&tmpbuf);
829       } else {
830         attrs = silc_calloc(1, sizeof(*attrs));
831       }
832
833       /* Call monitor */
834       if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) {
835         mdata.name = path;
836         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata,
837                            server->monitor_context);
838       }
839
840       /* Setstat operation */
841       server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
842                                    silc_sftp_server_status, (void *)id);
843
844       silc_sftp_attr_free(attrs);
845       silc_free(path);
846     }
847     break;
848
849   case SILC_SFTP_FSETSTAT:
850     {
851       unsigned char *hdata, *attr_buf;
852       SilcUInt32 hdata_len, attr_len = 0;
853       SilcBufferStruct tmpbuf;
854
855       SILC_LOG_DEBUG(("Fsetstat request"));
856
857       ret = silc_buffer_unformat(&buf,
858                                  SILC_STR_UI_INT(&id),
859                                  SILC_STR_UI32_NSTRING(&hdata, 
860                                                        &hdata_len),
861                                  SILC_STR_UI32_NSTRING(&attr_buf,
862                                                        &attr_len),
863                                  SILC_STR_END);
864       if (ret < 0)
865         goto failure;
866
867       if (attr_len) {
868         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
869         attrs = silc_sftp_attr_decode(&tmpbuf);
870       } else {
871         attrs = silc_calloc(1, sizeof(*attrs));
872       }
873
874       /* Get the handle */
875       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
876                                                (const unsigned char *)hdata,
877                                                hdata_len);
878       if (!handle) {
879         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
880         break;
881       }
882
883       /* Call monitor */
884       if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) {
885         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata,
886                            server->monitor_context);
887       }
888
889       /* Fsetstat operation */
890       server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, 
891                                     handle, attrs,
892                                     silc_sftp_server_status, (void *)id);
893
894       silc_sftp_attr_free(attrs);
895     }
896     break;
897
898   case SILC_SFTP_READLINK:
899     {
900       SILC_LOG_DEBUG(("Readlink request"));
901
902       ret = silc_buffer_unformat(&buf,
903                                  SILC_STR_UI_INT(&id),
904                                  SILC_STR_UI32_STRING_ALLOC(&path),
905                                  SILC_STR_END);
906       if (ret < 0)
907         goto failure;
908
909       /* Call monitor */
910       if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) {
911         mdata.name = path;
912         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata,
913                            server->monitor_context);
914       }
915
916       /* Readlink operation */
917       server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
918                                     silc_sftp_server_name, (void *)id);
919
920       silc_free(path);
921     }
922     break;
923
924   case SILC_SFTP_SYMLINK:
925     {
926       char *target = NULL;
927
928       SILC_LOG_DEBUG(("Symlink request"));
929
930       ret = silc_buffer_unformat(&buf,
931                                  SILC_STR_UI_INT(&id),
932                                  SILC_STR_UI32_STRING_ALLOC(&path),
933                                  SILC_STR_UI32_STRING_ALLOC(&target),
934                                  SILC_STR_END);
935       if (ret < 0)
936         goto failure;
937
938       /* Call monitor */
939       if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) {
940         mdata.name = path;
941         mdata.name2 = target;
942         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata,
943                            server->monitor_context);
944       }
945
946       /* Symlink operation */
947       server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
948                                    silc_sftp_server_status, (void *)id);
949
950       silc_free(path);
951       silc_free(target);
952     }
953     break;
954
955   case SILC_SFTP_REALPATH:
956     {
957       SILC_LOG_DEBUG(("Realpath request"));
958
959       ret = silc_buffer_unformat(&buf,
960                                  SILC_STR_UI_INT(&id),
961                                  SILC_STR_UI32_STRING_ALLOC(&path),
962                                  SILC_STR_END);
963       if (ret < 0)
964         goto failure;
965
966       /* Call monitor */
967       if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) {
968         mdata.name = path;
969         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata,
970                            server->monitor_context);
971       }
972
973       /* Realpath operation */
974       server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
975                                     silc_sftp_server_name, (void *)id);
976
977       silc_free(path);
978     }
979     break;
980
981   case SILC_SFTP_EXTENDED:
982     {
983       char *request = NULL;
984       unsigned char *data;
985       SilcUInt32 data_len;
986
987       SILC_LOG_DEBUG(("Extended request"));
988
989       ret = silc_buffer_unformat(&buf,
990                                  SILC_STR_UI_INT(&id),
991                                  SILC_STR_UI32_STRING_ALLOC(&request),
992                                  SILC_STR_END);
993       if (ret < 0)
994         goto failure;
995
996       data_len = 8 + strlen(request);
997       silc_buffer_pull(&buf, data_len);
998       ret = silc_buffer_unformat(&buf,
999                                  SILC_STR_UI_XNSTRING(&data, buf.len),
1000                                  SILC_STR_END);
1001       if (ret < 0)
1002         goto failure;
1003       data_len = buf.len;
1004
1005       /* Call monitor */
1006       if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
1007         (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata,
1008                            server->monitor_context);
1009       }
1010
1011       /* Extended operation */
1012       server->fs->fs->sftp_extended(server->fs->fs_context, sftp, 
1013                                     request, data, data_len,
1014                                     silc_sftp_server_extended, (void *)id);
1015
1016       silc_free(request);
1017     }
1018     break;
1019
1020   default:
1021     break;
1022   }
1023
1024   return;
1025
1026  failure:
1027   silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
1028 }