Back to index

avfs  1.0.1
dav_ls.c
Go to the documentation of this file.
00001 /* 
00002    ls for AVFS DAV support.
00003   
00004    Most of this file is taken from ls.c in cadaver, which has the
00005    following copyright notice:
00006 
00007    'ls' for cadaver
00008    Copyright (C) 2000-2001, Joe Orton <joe@orton.demon.co.uk>, 
00009    except where otherwise indicated.
00010                                    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015   
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020   
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 */
00025 
00026 #include "filebuf.h"
00027 
00028 #include <time.h>
00029 #include <http_request.h>
00030 #include <dav_props.h>
00031 #include <uri.h>
00032 #include <ne_alloc.h>
00033 
00034 #include <string.h>
00035 #include <stdlib.h>
00036 #include "dav.h"
00037 
00038 struct fetch_context {
00039   struct av_dav_conn *conn;
00040   struct av_dav_resource **list;
00041   const char *target; /* Request-URI of the PROPFIND */
00042   unsigned int include_target; /* Include resource at href */
00043 };  
00044 
00045 static const dav_propname flat_props[] = {
00046   { "DAV:", "getcontentlength" },
00047   { "DAV:", "getlastmodified" },
00048   { "DAV:", "displayname" },
00049   { "http://apache.org/dav/props/", "executable" },
00050   { NULL }
00051 };
00052 
00053 static const dav_propname complex_props[] = {
00054   { "DAV:", "resourcetype" },
00055   { NULL }
00056 };
00057 
00058 #define ELM_resourcetype (DAV_ELM_207_UNUSED + 1)
00059 #define ELM_collection (DAV_ELM_207_UNUSED + 4)
00060 
00061 static const struct hip_xml_elm complex_elms[] = {
00062   { "DAV:", "resourcetype", ELM_resourcetype, 0 },
00063   { "DAV:", "collection", ELM_collection, 0 },
00064   { NULL }
00065 };
00066 
00067 static int compare_resource(const struct av_dav_resource *r1, 
00068               const struct av_dav_resource *r2)
00069 {
00070   /* Sort errors first, then collections, then alphabetically */
00071   if (r1->type == resr_error) {
00072     return -1;
00073   } else if (r2->type == resr_error) {
00074     return 1;
00075   } else if (r1->type == resr_collection) {
00076     if (r2->type != resr_collection) {
00077       return -1;
00078     } else {
00079       return strcmp(r1->uri, r2->uri);
00080     }
00081   } else {
00082     if (r2->type != resr_collection) {
00083       return strcmp(r1->uri, r2->uri);
00084     } else {
00085       return 1;
00086     }
00087   }
00088 }
00089 
00090 static void results(void *userdata, const char *uri,
00091           const dav_prop_result_set *set)
00092 {
00093   struct fetch_context *ctx = userdata;
00094   struct av_dav_resource *current, *previous, *newres;
00095   const char *clength, *modtime, *isexec, *abspath;
00096   const http_status *status = NULL;
00097   
00098   av_log (AVLOG_DEBUG, "DAV URI: %s", uri);
00099 
00100   newres = dav_propset_private(set);
00101   abspath = uri_abspath(uri);
00102 
00103   if (uri_compare(ctx->target, abspath) == 0 && !ctx->include_target) {
00104     /* This is the target URI, skip it */
00105     av_free(newres);
00106     return;
00107   }
00108 
00109   newres->uri = ne_strdup(abspath);
00110 
00111   clength = dav_propset_value(set, &flat_props[0]);  
00112   modtime = dav_propset_value(set, &flat_props[1]);
00113   isexec = dav_propset_value(set, &flat_props[2]);
00114   
00115   if (clength == NULL)
00116     status = dav_propset_status(set, &flat_props[0]);
00117   if (modtime == NULL)
00118     status = dav_propset_status(set, &flat_props[1]);
00119 
00120   if (newres->type == resr_normal && status) {
00121     /* It's an error! */
00122     newres->error_status = status->code;
00123 
00124     /* Special hack for Apache 1.3/mod_dav */
00125     if (strcmp(status->reason_phrase, "status text goes here") == 0) {
00126       const char *desc;
00127       if (status->code == 401) {
00128         desc = ("Authorization Required");
00129       } else if (status->klass == 3) {
00130         desc = ("Redirect");
00131       } else if (status->klass == 5) {
00132         desc = ("Server Error");
00133       } else {
00134         desc = ("Unknown Error");
00135       }
00136       newres->error_reason = ne_strdup(desc);
00137     } else {
00138       newres->error_reason = ne_strdup(status->reason_phrase);
00139     }
00140     newres->type = resr_error;
00141   }
00142 
00143   if (isexec && strcasecmp(isexec, "T") == 0) {
00144     newres->is_executable = 1;
00145   } else {
00146     newres->is_executable = 0;
00147   }
00148 
00149   if (modtime)
00150     newres->modtime = http_dateparse(modtime);
00151 
00152   if (clength)
00153     newres->size = strtol(clength, NULL, 10);
00154 
00155   for (current = *ctx->list, previous = NULL; current != NULL; 
00156      previous = current, current=current->next) {
00157     if (compare_resource(current, newres) >= 0) {
00158       break;
00159     }
00160   }
00161   if (previous) {
00162     previous->next = newres;
00163   } else {
00164     *ctx->list = newres;
00165   }
00166   newres->next = current;
00167 }
00168 
00169 static int end_element(void *userdata, const struct hip_xml_elm *elm, const char *cdata)
00170 {
00171   dav_propfind_handler *pfh = userdata;
00172   struct av_dav_resource *r = dav_propfind_current_private(pfh);
00173 
00174   if (r == NULL) {
00175     return 0;
00176   }
00177 
00178   if (elm->id == ELM_collection) {
00179     r->type = resr_collection;
00180   }
00181 
00182   return 0;
00183 }
00184 
00185 static int check_context(hip_xml_elmid parent, hip_xml_elmid child)
00186 {
00187   if ((parent == DAV_ELM_prop && child == ELM_resourcetype) ||
00188     (parent == ELM_resourcetype && child == ELM_collection))
00189   {
00190     return 0;
00191   }
00192   return 0;  
00193 }
00194 
00195 void free_resource(struct av_dav_resource *res)
00196 {
00197   HTTP_FREE(res->uri);
00198   HTTP_FREE(res->displayname);
00199   HTTP_FREE(res->error_reason);
00200   av_free(res);
00201 }
00202 
00203 void free_resource_list(struct av_dav_resource *res)
00204 {
00205   struct av_dav_resource *next;
00206   for (; res != NULL; res = next) {
00207     next = res->next;
00208     free_resource(res);
00209   }
00210 }
00211 
00212 static void *create_private(void *userdata, const char *uri)
00213 {
00214   return ne_calloc(sizeof(struct av_dav_resource));
00215 }
00216 
00217 int fetch_resource_list(struct av_dav_conn *conn,
00218                 const char *uri, int depth, int include_target,
00219                 struct av_dav_resource **reslist)
00220 {
00221   dav_propfind_handler *pfh = dav_propfind_create(conn->sesh, uri, depth);
00222   int ret;
00223   struct fetch_context ctx = {0};
00224   
00225   *reslist = NULL;
00226   ctx.conn = conn;
00227   ctx.list = reslist;
00228   ctx.target = uri;
00229   ctx.include_target = include_target;
00230 
00231   dav_propfind_set_flat(pfh, flat_props);
00232 
00233   hip_xml_push_handler(dav_propfind_get_parser(pfh), complex_elms, 
00234              check_context, NULL, end_element, pfh);
00235 
00236   dav_propfind_set_complex(pfh, complex_props, create_private, NULL);
00237 
00238   ret = dav_propfind_named(pfh, results, &ctx);
00239 
00240   dav_propfind_destroy(pfh);
00241 
00242   return ret;
00243 }