1 /* pfs-dav.c:
2  *
3  ****************************************************************
4  * Copyright (C) 2002, 2003 Scott Parish
5  * Copyright (C) 2003 Tom Lord
6  *
7  * See the file "COPYING" for further information about
8  * the copyright and warranty status of this work.
9  */
10 
11 
12 #include <string.h>
13 #include "hackerlab/bugs/panic.h"
14 #include "hackerlab/mem/alloc-limits.h"
15 #include "hackerlab/mem/mem.h"
16 #include "hackerlab/char/str.h"
17 #include "hackerlab/fmt/cvt.h"
18 #include "hackerlab/fs/file-names.h"
19 #include "hackerlab/vu/safe.h"
20 #include "tla/libfsutils/tmp-files.h"
21 #include "tla/libfsutils/file-contents.h"
22 #include "tla/libarch/archives.h"
23 #include "tla/libarch/pfs-dav.h"
24 #include "libneon/src/ne_session.h"
25 #include "libneon/src/ne_basic.h"
26 #include "libneon/src/ne_request.h"
27 #include "libneon/src/ne_auth.h"
28 #include "libneon/src/ne_props.h"
29 #include "libneon/src/ne_uri.h"
30 #include "libneon/src/ne_redirect.h"
31 #include "libneon/src/ne_socket.h"
32 
33 
34 
35 #undef MIN
36 #define MIN(A,B) ((A) < (B) ? (A) : (B))
37 #define LISTING_FILE ".listing"
38 
39 static const ne_propname ls_props[] =
40 {
41   { "DAV:", "getcontentlength" },
42   { "DAV:", "getlastmodified" },
43   { "DAV:", "resourcetype" },
44   { NULL }
45 };
46 
47 struct authinfo
48 {
49   char *username;
50   char *password;
51 };
52 
53 struct ls_data
54 {
55   char *files;
56   char *uri;
57 };
58 
59 struct dav_is_dir_ls_data
60 {
61   char *uri;
62   int is_dir;
63 };
64 
65 
66 struct arch_pfs_dav_session
67 {
68   struct arch_pfs_session pfs;
69 
70   char * cwd;
71   char * dav_scheme;
72   char * dav_hostname;
73   int dav_port;
74 
75   ne_session * sess;
76   ne_server_capabilities sess_opts;
77 };
78 
79 
80 /* __STDC__ prototypes for static functions */
81 static t_uchar * pfs_file_contents (struct arch_pfs_session * p,
82                                     const t_uchar * path,
83                                     int soft_errors);
84 static rel_table pfs_directory_files (struct arch_pfs_session * p,
85                                       const t_uchar * path,
86                                       int soft_errors);
87 static int pfs_file_exists (struct arch_pfs_session * p,
88                             const t_uchar * path);
89 static int pfs_get_file (struct arch_pfs_session * p,
90                          int out_fd,
91                          const t_uchar * path,
92                          int soft_errors);
93 static int pfs_put_file (struct arch_pfs_session * p,
94                          const t_uchar * path,
95                          mode_t perms,
96                          int in_fd,
97                          int soft_errors);
98 static int pfs_mkdir (struct arch_pfs_session * p,
99                       const t_uchar * path,
100                       mode_t mode,
101                       int soft_errors);
102 static int pfs_rename (struct arch_pfs_session * p,
103                        t_uchar ** errstr,
104                        const t_uchar * from,
105                        const t_uchar * to,
106                        int soft_errors);
107 static int pfs_is_dir (struct arch_pfs_session * p,
108                        const t_uchar * path);
109 static int dav_is_dir (struct arch_pfs_dav_session * pfs,
110                        const char * dir);
111 static int pfs_rmdir (struct arch_pfs_session * p,
112                       const t_uchar * path,
113                       int soft_errors);
114 static int pfs_rm (struct arch_pfs_session * p,
115                    const t_uchar * path,
116                    int soft_errors);
117 static void dav_is_dir_results (void * userdata,
118                                 const char * uri,
119                                 const ne_prop_result_set * set);
120 static int dav_client_cwd (struct arch_pfs_dav_session * pfs,
121                            const t_uchar * path);
122 static int dav_client_auth (void * userdata,
123                             const char * realm,
124                             int attempt,
125                             char * username,
126                             char * password);
127 static t_uchar * abs_path (const t_uchar * cwd,
128                            const t_uchar * path);
129 static t_uchar * dirfold (t_uchar *dir);
130 static void results (void * userdata,
131                      const char * uri,
132                      const ne_prop_result_set * set);
133 
134 
135 
136 struct arch_pfs_vtable dav_pfs_fns =
137 {
138   pfs_file_exists,
139   pfs_is_dir,
140 
141   pfs_file_contents,
142   pfs_get_file,
143   pfs_directory_files,
144 
145   pfs_put_file,
146 
147   pfs_mkdir,
148   pfs_rename,
149 
150   pfs_rmdir,
151   pfs_rm,
152 };
153 
154 
155 
156 
157 int
arch_pfs_dav_supported_protocol(const t_uchar * uri)158 arch_pfs_dav_supported_protocol (const t_uchar * uri)
159 {
160   if (!str_cmp_prefix ("http:", uri) ||
161       !str_cmp_prefix ("https:", uri))
162     return 1;
163   else
164     return 0;
165 }
166 
167 
168 struct arch_pfs_session *
arch_pfs_dav_connect(const t_uchar * uri)169 arch_pfs_dav_connect (const t_uchar * uri)
170 {
171   int ign;
172   struct arch_pfs_dav_session * answer = 0;
173   t_uchar * host;
174   t_uchar * user;
175   t_uchar * passwd;
176   t_uchar * hostname;
177   t_uchar * portstr;
178   t_uchar * root_path = 0;
179   t_uchar * proxy;
180   t_uchar * proxy_port;
181   struct authinfo * auth = 0;
182   int proxy_port_num;
183 
184   /* ne_sock_init() is idempotent, so just init always */
185   if (ne_sock_init ())
186     {
187       panic ("arch_pfs_dav_connect: ne_sock_init() failed.");
188     }
189 
190   answer = (struct arch_pfs_dav_session *)lim_malloc (0, sizeof (*answer));
191   mem_set0 ((t_uchar *)answer, sizeof (*answer));
192   answer->pfs.vtable = &dav_pfs_fns;
193 
194   if (!str_cmp_prefix ("http://", uri))
195     {
196       answer->dav_scheme = str_save (0, "http");
197       host = str_save (0, uri + sizeof ("http://") - 1);
198     }
199   else if (!str_cmp_prefix ("https://", uri))
200     {
201       answer->dav_scheme = str_save (0, "https");
202       host = str_save (0, uri + sizeof ("https://") - 1);
203     }
204   else
205     panic ("bogus uri to arch_pfs_dav_connect");
206 
207   root_path = str_chr_index (host, '/');
208   if (root_path)
209     {
210       t_uchar * pos;
211       pos = root_path;
212       root_path = str_save (0, root_path);
213       *pos = 0;
214     }
215 
216   hostname = str_chr_index (host, '@');
217 
218   if (!hostname)
219     {
220       answer->dav_hostname = str_save (0, host);
221     }
222   else
223     {
224       user = host;
225       auth = lim_malloc (0, sizeof (struct authinfo));
226 
227       passwd = str_chr_index_n (user, hostname - user, ':');
228       if (passwd++)
229         {
230           auth->username = str_save_n (0, user, (passwd - 1) - user);
231           auth->password = str_save_n (0, passwd, hostname - passwd);
232         }
233       else
234         {
235           auth->username = str_save_n (0, user, hostname - user);
236           auth->password = str_save (0, "");
237         }
238 
239       answer->dav_hostname = str_save (0, hostname + 1);
240     }
241 
242   portstr = str_chr_index (answer->dav_hostname, ':');
243    if (portstr)
244      *(portstr++) = 0;
245 
246   answer->dav_port = ne_uri_defaultport (answer->dav_scheme);
247   if (portstr && (0 > cvt_decimal_to_uint (&ign, &answer->dav_port, portstr, str_length (portstr))))
248     {
249       safe_printfmt (2, "illegal port number in uri -- %s\n", uri);
250       exit (2);
251     }
252 
253 
254   answer->sess = ne_session_create (answer->dav_scheme, answer->dav_hostname, answer->dav_port);
255 
256   if (!str_cmp ("https", answer->dav_scheme))
257     {
258       ne_ssl_trust_default_ca (answer->sess);
259     }
260 
261   if (auth)
262     {
263       ne_set_server_auth (answer->sess, dav_client_auth, auth);
264     }
265 
266   ne_set_useragent (answer->sess, "arch-client/0.1");
267 
268   /*
269    * Retrieve the proxy. Do not alter the environment variable.
270    * The proxy variable is formatted as
271    * scheme://host:port/
272    * We only support http as the scheme.
273    */
274   proxy = getenv ("http_proxy");
275   if (proxy)
276     proxy = str_save (0, proxy);
277   else
278     {
279       proxy = getenv ("HTTP_PROXY");
280       if (proxy)
281         proxy = str_save (0, proxy);
282     }
283 
284   if (proxy && !str_cmp_prefix ("http://", proxy))
285     {
286       t_uchar * proxy_path = proxy + 7;
287       proxy_port = str_chr_index (proxy_path, ':');
288 
289       if (proxy_port)
290         {
291 	  unsigned proxy_port_len;
292 
293           *proxy_port++ = 0;
294 
295 	  proxy_port_len = str_length (proxy_port);
296 	  /* The port may be followed by a trailing slash (according to
297 	     rcollins, it _must_ be followed by a slash, strictly speaking,
298 	     but this restriction is widely ignored both by software and by
299 	     users, so it's not practical to enforce it, and there's no
300 	     real gain from doing so).  */
301 	  if (proxy_port_len > 0 && proxy_port[proxy_port_len - 1] == '/')
302 	    proxy_port_len--;
303 
304           if (cvt_decimal_to_int (&ign, &proxy_port_num, proxy_port, proxy_port_len))
305             {
306               safe_printfmt (2, "ill formated http proxy port number from $http_proxy\n");
307               exit (2);
308             }
309 
310           ne_session_proxy (answer->sess, proxy_path, proxy_port_num);
311         }
312 
313       if (proxy)
314 	{
315 	  t_uchar * proxy_user;
316 	  t_uchar * proxy_passwd;
317 	  proxy_user = getenv("proxy_user");
318 	  proxy_passwd = getenv("proxy_passwd");
319 	  if ((proxy_passwd != NULL) && (proxy_user != NULL))
320 	    {
321 	      struct authinfo * proxy_auth = 0;
322 	      proxy_auth = lim_malloc (0, sizeof (struct authinfo));
323 	      if (proxy_auth)
324 		{
325 		  proxy_auth->username = str_save(0, proxy_user);
326 		  proxy_auth->password = str_save(0, proxy_passwd);
327 		  ne_set_proxy_auth(answer->sess, dav_client_auth, proxy_auth);
328 		}
329 	    }
330 	}
331     }
332 
333   if (root_path)
334     dav_client_cwd (answer, root_path);
335 
336   lim_free (0, host);
337   lim_free (0, root_path);
338   lim_free (0, proxy);
339 
340   return (struct arch_pfs_session *)answer;
341 }
342 
343 
344 static t_uchar *
pfs_file_contents(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)345 pfs_file_contents (struct arch_pfs_session * p,
346                    const t_uchar * path,
347                    int soft_errors)
348 {
349   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
350   t_uchar * tmp_path = 0;
351   int fd;
352   t_uchar * dav_path = 0;
353   int ne_err;
354   t_uchar * answer = 0;
355 
356   tmp_path = tmp_file_name ("/tmp", ",,pfs-dav-file-contents");
357   fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
358   safe_unlink (tmp_path);
359 
360   dav_path = abs_path (pfs->cwd, (char *)path);
361   ne_err = ne_get (pfs->sess, dav_path, fd);
362   if (ne_err)
363     {
364       if (!soft_errors)
365         {
366           safe_printfmt (2, "webdav error: %s\n", ne_get_error (pfs->sess));
367           exit (2);
368         }
369     }
370   else
371     {
372       safe_lseek (fd, (off_t)0, SEEK_SET);
373       answer = fd_contents (fd);
374     }
375 
376   safe_close (fd);
377   lim_free (0, dav_path);
378 
379   return answer;
380 }
381 
382 
383 static rel_table
pfs_directory_files(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)384 pfs_directory_files (struct arch_pfs_session * p,
385                      const t_uchar * path,
386                      int soft_errors)
387 {
388   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
389   int ne_err;
390   t_uchar * dir = 0;
391   t_uchar * file_string = 0;
392   rel_table answer = rel_table_nil;
393 
394   if (pfs->sess_opts.dav_class1)
395     {
396       struct ls_data data;
397 
398       dir = abs_path (pfs->cwd, path);
399 
400       if (dir[str_length (dir) - 1] != '/')
401         dir = str_realloc_cat(0, dir, "/");
402 
403       data.files = str_save (0, "");;
404       data.uri = dir;
405 
406       if ((ne_err = ne_simple_propfind (pfs->sess, dir, NE_DEPTH_ONE, ls_props, results, &data)))
407         {
408           if (!soft_errors)
409             {
410               safe_printfmt (2, "webdav error (directory_files): %s (%s)\n", dir, ne_get_error (pfs->sess));
411               exit (2);
412             }
413         }
414       else
415         {
416           file_string = str_save (0, data.files);
417         }
418 
419       lim_free (0, data.files);
420     }
421   else
422     {
423       dir = file_name_in_vicinity (0, path, LISTING_FILE);
424 
425       file_string = pfs_file_contents (p, dir, 1);
426     }
427 
428 
429   answer = rel_ws_split (file_string);
430 
431   lim_free (0, dir);
432   lim_free (0, file_string);
433 
434   return answer;
435 }
436 
437 
438 static int
pfs_file_exists(struct arch_pfs_session * p,const t_uchar * path)439 pfs_file_exists (struct arch_pfs_session * p,
440                  const t_uchar * path)
441 {
442   t_uchar * path_dir = 0;
443   t_uchar * path_tail = 0;
444   rel_table files = rel_table_nil;
445   int answer = 0;
446   int x;
447 
448   /* There is probably a better way to do this in webdav. */
449 
450   path_dir = file_name_directory_file (0, path);
451   if (!path_dir)
452     {
453       path_dir = str_save (0, ".");
454     }
455 
456   path_tail = file_name_tail (0, path);
457 
458   files = pfs_directory_files (p, path_dir, 1);
459 
460   for (x = 0; x < rel_n_records (files); ++x)
461     {
462       if (!str_cmp (path_tail, rel_peek_str (files, x, 0)))
463         {
464           answer = 1;
465           break;
466         }
467     }
468 
469 
470   lim_free (0, path_dir);
471   lim_free (0, path_tail);
472   rel_free_table (files);
473 
474   return answer;
475 }
476 
477 
478 static int
pfs_get_file(struct arch_pfs_session * p,int out_fd,const t_uchar * path,int soft_errors)479 pfs_get_file (struct arch_pfs_session * p,
480               int out_fd,
481               const t_uchar * path,
482               int soft_errors)
483 {
484   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
485   t_uchar * dav_path = 0;
486   int ne_err;
487   int answer = 0;
488 
489 
490   dav_path = abs_path (pfs->cwd, (char *)path);
491   ne_err = ne_get (pfs->sess, dav_path, out_fd);
492   if (ne_err)
493     {
494       if (!soft_errors)
495         {
496           safe_printfmt (2, "webdav error: %s\n", ne_get_error (pfs->sess));
497           exit (2);
498         }
499       else
500         answer = -1;
501     }
502 
503   lim_free (0, dav_path);
504   return answer;
505 }
506 
507 
508 static int
pfs_put_file(struct arch_pfs_session * p,const t_uchar * path,mode_t perms,int in_fd,int soft_errors)509 pfs_put_file (struct arch_pfs_session * p,
510               const t_uchar * path,
511               mode_t perms,
512               int in_fd,
513               int soft_errors)
514 {
515   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
516   int ne_err;
517   t_uchar * file;
518   int answer = 0;
519 
520   file = abs_path (pfs->cwd, path);
521 
522   ne_err = ne_put (pfs->sess, file, in_fd);
523 
524   if (ne_err)
525     {
526       if (!soft_errors)
527         {
528           safe_printfmt (2, "webdav error(put_file): writing to %s (%s)\n", file, ne_get_error (pfs->sess));
529           exit (2);
530         }
531       else
532         {
533           answer = -1;
534         }
535     }
536 
537   lim_free (0, file);
538 
539   return answer;
540 }
541 
542 
543 static int
pfs_mkdir(struct arch_pfs_session * p,const t_uchar * path,mode_t mode,int soft_errors)544 pfs_mkdir (struct arch_pfs_session * p,
545            const t_uchar * path,
546            mode_t mode,
547            int soft_errors)
548 {
549   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
550   int ne_err;
551   t_uchar * dir = 0;
552   int answer = 0;
553 
554   dir = abs_path (pfs->cwd, path);
555   if (dir[str_length (dir) - 1] != '/')
556     dir = str_realloc_cat (0, dir, "/");
557 
558   if ((ne_err = ne_mkcol (pfs->sess, dir)))
559     {
560       if (!soft_errors)
561         {
562           safe_printfmt (2, "webdav error (pfs_mkdir): %s (%s)\n", path, ne_get_error (pfs->sess));
563           exit (2);
564         }
565       else
566         answer = -1;
567     }
568 
569   lim_free (0, dir);
570   return answer;
571 }
572 
573 
574 static int
pfs_rename(struct arch_pfs_session * p,t_uchar ** errstr,const t_uchar * from,const t_uchar * to,int soft_errors)575 pfs_rename (struct arch_pfs_session * p,
576             t_uchar ** errstr,
577             const t_uchar * from,
578             const t_uchar * to,
579             int soft_errors)
580 {
581   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
582   int ne_err;
583   int ret;
584   t_uchar * from2;
585   t_uchar * to2;
586   int result = 0;
587 
588   from2 = abs_path (pfs->cwd, from);
589   to2 = abs_path (pfs->cwd, to);
590 
591   ret = dav_is_dir (pfs, from2);
592   if (ret == -1)
593     {
594       if (errstr)
595         *errstr = str_save (0, "file does not exist for rename");
596       result = -1;
597     }
598   else
599     {
600       if (ret)
601         {
602           if (from2[str_length (from2) - 1] != '/')
603             from2 = str_realloc_cat (0, from2, "/");
604           if (to2[str_length (to2) - 1] != '/')
605             to2 = str_realloc_cat (0, to2, "/");
606         }
607 
608       if (0 < dav_is_dir (pfs, to2))
609         {
610           char * b;
611           char * file;
612 
613           b = file = str_save (0, from);
614         filename:
615           file = str_chr_rindex (file, '/');
616           if (!file)
617             file = b;
618           else if (!file[1])
619             {
620               file[0] = 0;
621               goto filename;
622             }
623           else
624             file++;
625 
626           to2 = str_realloc_cat_many (0, to2, "/", file, str_end);
627           lim_free (0, b);
628         }
629 
630 
631       if ((ne_err = ne_move (pfs->sess, 0, from2, to2)))
632         {
633           if (errstr)
634             *errstr = str_save (0, ne_get_error (pfs->sess));
635           result = -1;
636         }
637     }
638 
639   lim_free (0, from2);
640   lim_free (0, to2);
641   return result;
642 }
643 
644 
645 static int
pfs_is_dir(struct arch_pfs_session * p,const t_uchar * path)646 pfs_is_dir (struct arch_pfs_session * p,
647             const t_uchar * path)
648 {
649   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
650   t_uchar * abs = 0;
651   int answer;
652 
653   abs = abs_path (pfs->cwd, path);
654 
655   answer = dav_is_dir (pfs, abs);
656 
657   lim_free (0, abs);
658 
659   return answer;
660 }
661 
662 
663 static int
dav_is_dir(struct arch_pfs_dav_session * pfs,const char * dir)664 dav_is_dir (struct arch_pfs_dav_session * pfs,
665             const char * dir)
666 {
667   char * filename;
668   char * parent;
669   struct dav_is_dir_ls_data data;
670   int ne_err;
671   int answer;
672 
673   parent = str_save (0, dir);
674   filename = str_chr_rindex (parent, '/');
675   filename[1] = 0;
676 
677   /* `const' discarded with hopes that libneon isn't obnoxious
678    */
679   data.uri = (char *)dir;
680   data.is_dir = 0;
681 
682   if((ne_err = ne_simple_propfind (pfs->sess, parent, NE_DEPTH_ONE, ls_props, dav_is_dir_results, &data)))
683     {
684       answer = -1;
685     }
686   else
687     {
688       answer = data.is_dir;
689     }
690 
691   lim_free (0, parent);
692   return answer;
693 }
694 
695 
696 static int
pfs_rmdir(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)697 pfs_rmdir (struct arch_pfs_session * p,
698            const t_uchar * path,
699            int soft_errors)
700 {
701   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
702   int ne_err;
703   t_uchar * dir = 0;
704   int answer = 0;
705 
706   dir = abs_path (pfs->cwd, path);
707   if (dir[str_length (dir) - 1] != '/')
708     dir = str_realloc_cat (0, dir, "/");
709 
710   if ((ne_err = ne_delete (pfs->sess, dir)))
711     {
712       if (!soft_errors)
713         {
714           safe_printfmt (2, "webdav error (pfs_rmdir): %s (%s)\n", dir, ne_get_error (pfs->sess));
715           exit (2);
716         }
717       else
718         answer = -1;
719     }
720 
721   lim_free (0, dir);
722 
723   return answer;
724 }
725 
726 
727 static int
pfs_rm(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)728 pfs_rm (struct arch_pfs_session * p,
729         const t_uchar * path,
730         int soft_errors)
731 {
732   struct arch_pfs_dav_session * pfs = (struct arch_pfs_dav_session *)p;
733   int ne_err;
734   t_uchar * abs = 0;
735   int answer = 0;
736 
737   abs = abs_path (pfs->cwd, path);
738 
739   if ((ne_err = ne_delete (pfs->sess, abs)))
740     {
741       if (!soft_errors)
742         {
743           safe_printfmt (2, "webdav error (pfs_rm): %s (%s)\n", path, ne_get_error (pfs->sess));
744           exit (2);
745         }
746       else
747         answer = -1;
748     }
749 
750   lim_free (0, abs);
751   return 0;
752 }
753 
754 
755 
756 
757 static void
dav_is_dir_results(void * userdata,const char * uri,const ne_prop_result_set * set)758 dav_is_dir_results (void * userdata,
759                     const char * uri,
760                     const ne_prop_result_set * set)
761 {
762   struct dav_is_dir_ls_data * data = (struct dav_is_dir_ls_data *)userdata;
763   int len;
764 
765   len = str_length (data->uri);
766   if (!str_cmp_n (uri, len, data->uri, len))
767     {
768       if (uri[str_length (uri) - 1] == '/')
769         data->is_dir = 1;
770       else
771         data->is_dir = 0;
772     }
773 }
774 
775 
776 static int
dav_client_cwd(struct arch_pfs_dav_session * pfs,const t_uchar * path)777 dav_client_cwd (struct arch_pfs_dav_session * pfs,
778                 const t_uchar * path)
779 {
780   int ne_err;
781   t_uchar * tmp;
782   t_uchar * dir;
783 
784   dir = abs_path (pfs->cwd, path);
785   if (dir[str_length (dir) - 1] != '/')
786     dir = str_realloc_cat (0, dir, "/");
787 
788 #if 1
789   if (getenv("TLA_DISABLE_DAV")!=NULL) {
790       pfs->sess_opts.dav_class1 = 0;
791       pfs->sess_opts.dav_class2 = 0;
792       pfs->sess_opts.dav_executable = 0;
793   } else
794 #endif
795 
796   if ((ne_err = ne_options (pfs->sess, dir, &pfs->sess_opts)))
797     {
798       /* if error assume that server doesn't implement OPTIONS */
799       pfs->sess_opts.dav_class1 = 0;
800       pfs->sess_opts.dav_class2 = 0;
801       pfs->sess_opts.dav_executable = 0;
802     }
803 
804   if (pfs->sess_opts.dav_class1) /* if the server supports DAV */
805     {
806       if ((ne_err = ne_simple_propfind (pfs->sess, dir, NE_DEPTH_ONE, ls_props, NULL, NULL)))
807         {
808           safe_printfmt (2, "webdav error: %s\n", ne_get_error (pfs->sess));
809           exit (2);
810         }
811     }
812   else /* no dav, so look for a listing file */
813     {
814       time_t mtime;
815       char * dirlisting = 0;
816 
817       dirlisting = str_alloc_cat (0, dir, LISTING_FILE);
818 
819       if ((ne_err = ne_getmodtime (pfs->sess, dirlisting, &mtime)))
820         {
821           safe_printfmt (2, "unable to access URL: %s\nwebdav error: %s\n", dirlisting, ne_get_error (pfs->sess));
822           exit (2);
823         }
824       lim_free (0, dirlisting);
825     }
826 
827   tmp = ne_path_unescape (dir);
828   lim_free (0, dir);
829   if (pfs->cwd)
830     free (pfs->cwd);
831   pfs->cwd = tmp;
832 
833   return 0;
834 }
835 
836 
837 static int
dav_client_auth(void * userdata,const char * realm,int attempt,char * username,char * password)838 dav_client_auth (void * userdata,
839                  const char * realm,
840                  int attempt,
841                  char * username,
842                  char * password)
843 {
844   struct authinfo *auth;
845   int len;
846 
847   if (attempt > 1)
848     return attempt;
849 
850   auth = userdata;
851   len = str_length (auth->username);
852   str_cpy_n (username, auth->username, MIN (len, NE_ABUFSIZ - 1));
853   len = str_length (auth->password);
854   str_cpy_n (password, auth->password, MIN (len, NE_ABUFSIZ - 1));
855 
856   return 0;
857 }
858 
859 
860 static t_uchar *
abs_path(const t_uchar * cwd,const t_uchar * path)861 abs_path (const t_uchar * cwd,
862           const t_uchar * path)
863 {
864   t_uchar * file;
865   t_uchar * tmp;
866 
867   if (cwd == NULL)
868     cwd = "/";
869 
870   if (path[0] != '/')
871     file = str_alloc_cat (0, cwd, path);
872   else
873     file = str_save (0, path);
874 
875   dirfold (file);
876 
877   tmp = ne_path_escape (file);
878   lim_free (0, file);
879   file = str_save (0, tmp);
880   free (tmp);
881 
882   return file;
883 }
884 
885 
886 static t_uchar *
dirfold(t_uchar * dir)887 dirfold (t_uchar *dir)
888 {
889   t_uchar * buf;
890   t_uchar * this;
891   t_uchar * next;
892   int dir_i = 0;
893 
894   this = next = buf = str_save (0, dir);
895   while ((this = str_separate (&next, "/")) != NULL)
896     {
897       if (str_length (this) == 0 || (str_length (this) == 1 && this[0] == '.'))
898         continue;
899       else if (str_length (this) == 2 && *this == '.' && this[1] == '.')
900         {
901           if (dir_i > 0)
902             dir_i = (int)(strrchr (dir, '/') - (char *)dir);
903           dir[dir_i] = 0;
904         }
905       else
906         {
907           dir[dir_i++] = '/';
908           strcpy (dir + dir_i, this);
909           dir_i += str_length (this);
910         }
911     }
912   lim_free (0, buf);
913 
914   if (!str_length (dir))
915       str_cpy (dir, "/");
916 
917   return dir;
918 }
919 
920 
921 static void
results(void * userdata,const char * uri,const ne_prop_result_set * set)922 results (void * userdata,
923          const char * uri,
924          const ne_prop_result_set * set)
925 {
926   int n;
927   char * file, * tmp;
928   struct ls_data * data = userdata;
929 
930   if (str_cmp (data->uri, uri))
931     {
932       if (1 == (n = str_length (uri)))
933         return;
934 
935       if (uri[n - 1] == '/')
936         n--;
937 
938       file = str_chr_rindex_n (uri, n, '/') + 1;
939 
940       n = str_length (file);
941       if (file[n - 1] == '/')
942         n--;
943 
944       file = str_save_n (0, file, n);
945       tmp = ne_path_unescape (file);
946       lim_free (0, file);
947 
948       data->files = str_realloc_cat_many (0, data->files, tmp, "\r\n", str_end);
949       free (tmp);
950     }
951 }
952 
953 
954 
955 /* tag: Tom Lord Thu Jun  5 15:23:06 2003 (pfs-dav.c)
956  */
957