dirplex: Made it easier to include configuration "modules".
[ashd.git] / src / dirplex.c
index 01d8715..60f0859 100644 (file)
@@ -43,6 +43,9 @@
 #define PAT_ALL 2
 #define PAT_DEFAULT 3
 
+#define PT_FILE 0
+#define PT_DIR 1
+
 struct config {
     struct config *next, *prev;
     char *path;
@@ -59,6 +62,7 @@ struct rule {
 
 struct pattern {
     struct pattern *next;
+    int type;
     char *childnm;
     char **fchild;
     struct rule **rules;
@@ -169,6 +173,8 @@ static struct pattern *parsepattern(struct cfstate *s)
        return(NULL);
     }
     
+    if((s->argc > 1) && !strcmp(s->argv[1], "directory"))
+       pat->type = PT_DIR;
     sl = s->lno;
     while(1) {
        getcfline(s);
@@ -302,6 +308,9 @@ static struct config *getconfig(char *path)
     cf->mtime = mtime;
     cf->lastck = now;
     cf->next = cflist;
+    cf->prev = NULL;
+    if(cflist != NULL)
+       cflist->prev = cf;
     cflist = cf;
     return(cf);
 }
@@ -352,7 +361,7 @@ static struct child *findchild(char *file, char *name)
     return(ch);
 }
 
-static struct pattern *findmatch(char *file, int trydefault)
+static struct pattern *findmatch(char *file, int trydefault, int dir)
 {
     int i, o, c;
     char *bn;
@@ -367,6 +376,10 @@ static struct pattern *findmatch(char *file, int trydefault)
     cfs = getconfigs(file);
     for(c = 0; cfs[c] != NULL; c++) {
        for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) {
+           if(!dir && (pat->type == PT_DIR))
+               continue;
+           if(dir && (pat->type != PT_DIR))
+               continue;
            for(i = 0; (rule = pat->rules[i]) != NULL; i++) {
                if(rule->type == PAT_BASENAME) {
                    for(o = 0; rule->patterns[o] != NULL; o++) {
@@ -392,19 +405,16 @@ static struct pattern *findmatch(char *file, int trydefault)
                return(pat);
        }
     }
+    if(!trydefault)
+       return(findmatch(file, 1, dir));
     return(NULL);
 }
 
-static void handlefile(struct hthead *req, int fd, char *path)
+static void handle(struct hthead *req, int fd, char *path, struct pattern *pat)
 {
-    struct pattern *pat;
     struct child *ch;
 
     headappheader(req, "X-Ash-File", path);
-    if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) {
-       simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource.");
-       return;
-    }
     if(pat->fchild) {
        stdforkserve(pat->fchild, req, fd);
     } else {
@@ -418,6 +428,17 @@ static void handlefile(struct hthead *req, int fd, char *path)
     }
 }
 
+static void handlefile(struct hthead *req, int fd, char *path)
+{
+    struct pattern *pat;
+
+    if((pat = findmatch(path, 0, 0)) == NULL) {
+       simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource.");
+       return;
+    }
+    handle(req, fd, path, pat);
+}
+
 static void handledir(struct hthead *req, int fd, char *path)
 {
     struct config **cfs;
@@ -426,8 +447,10 @@ static void handledir(struct hthead *req, int fd, char *path)
     char *inm, *ipath, *p;
     DIR *dir;
     struct dirent *dent;
+    struct pattern *pat;
     
-    cfs = getconfigs(sprintf3("%s/", path));
+    path = sprintf2("%s/", path);
+    cfs = getconfigs(path);
     for(i = 0; cfs[i] != NULL; i++) {
        if(cfs[i]->index != NULL) {
            for(o = 0; cfs[i]->index[o] != NULL; o++) {
@@ -436,7 +459,7 @@ static void handledir(struct hthead *req, int fd, char *path)
                if(!stat(ipath, &sb) && S_ISREG(sb.st_mode)) {
                    handlefile(req, fd, ipath);
                    free(ipath);
-                   return;
+                   goto out;
                }
                free(ipath);
                
@@ -445,7 +468,7 @@ static void handledir(struct hthead *req, int fd, char *path)
                    while((dent = readdir(dir)) != NULL) {
                        if((p = strchr(dent->d_name, '.')) == NULL)
                            continue;
-                       if(strncmp(dent->d_name, inm, p - dent->d_name))
+                       if(strncmp(dent->d_name, inm, strlen(inm)))
                            continue;
                        ipath = sprintf2("%s/%s", path, dent->d_name);
                        if(stat(ipath, &sb) || !S_ISREG(sb.st_mode)) {
@@ -460,14 +483,20 @@ static void handledir(struct hthead *req, int fd, char *path)
                if(ipath != NULL) {
                    handlefile(req, fd, ipath);
                    free(ipath);
-                   return;
+                   goto out;
                }
            }
            break;
        }
     }
-    /* XXX: Directory listings */
+    if((pat = findmatch(path, 0, 1)) != NULL) {
+       handle(req, fd, path, pat);
+       goto out;
+    }
     simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory.");
+    
+out:
+    free(path);
 }
 
 static int checkdir(struct hthead *req, int fd, char *path)
@@ -491,6 +520,12 @@ static void serve(struct hthead *req, int fd)
        } else {
            *(p2++) = 0;
        }
+       if((tmp = unquoteurl(p)) == NULL) {
+           simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence.");
+           goto fail;
+       }
+       strcpy(p, tmp);
+       free(tmp);
        
        if(!*p) {
            if(p2 == NULL) {
@@ -605,7 +640,7 @@ int main(int argc, char **argv)
 {
     int c;
     int nodef;
-    char *gcf, *lcf;
+    char *gcf, *lcf, *clcf;
     struct hthead *req;
     int fd;
     
@@ -638,8 +673,18 @@ int main(int argc, char **argv)
        }
     }
     if(lcf != NULL) {
-       if((lconfig = readconfig(lcf)) == NULL)
-           exit(1);
+       if(strchr(lcf, '/') == NULL) {
+           if((clcf = findstdconf(sprintf3("ashd/%s", lcf))) == NULL) {
+               flog(LOG_ERR, "could not find requested configuration `%s'", lcf);
+               exit(1);
+           }
+           if((lconfig = readconfig(clcf)) == NULL)
+               exit(1);
+           free(clcf);
+       } else {
+           if((lconfig = readconfig(lcf)) == NULL)
+               exit(1);
+       }
     }
     if(chdir(argv[optind])) {
        flog(LOG_ERR, "could not change directory to %s: %s", argv[optind], strerror(errno));