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