changeset 67:ec671a7ea6e2

- * Improved the dpi framework. Now dpi-programs can be specified in dpidrc, and there's no need to touch dillo's sources to add new dpi services. Just make your dpi program, add a dpidrc line and play with it!
author jcid
date Thu, 06 Dec 2007 18:12:02 +0100
parents 99def3674546
children 043b53a25dc3
files ChangeLog dlib/dlib.c dlib/dlib.h dpid/Makefile.am dpid/dpid.c dpid/dpid.h dpid/main.c src/capi.c src/prefs.c
diffstat 9 files changed, 249 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Dec 05 16:39:22 2007 +0100
+++ b/ChangeLog	Thu Dec 06 18:12:02 2007 +0100
@@ -171,6 +171,10 @@
  - * Fixed a file descriptor leak in the dpi protocol library.
    * Fixed a subtle segfault bug with malformed URLs in cookies.c.
    Patch: Francis Daly
+ - * Improved the dpi framework. Now dpi-programs can be specified in dpidrc,
+   and there's no need to touch dillo's sources to add new dpi services.
+   Just make your dpi program, add a dpidrc line and play with it!
+   Patch: Diego Senz, Jorge Arellano
 
 
 dillo-0.8.5 [Jun 15, 2005]
--- a/dlib/dlib.c	Wed Dec 05 16:39:22 2007 +0100
+++ b/dlib/dlib.c	Thu Dec 06 18:12:02 2007 +0100
@@ -682,6 +682,50 @@
 }
 
 /*
+ *- Parse function ------------------------------------------------------------
+ */
+
+/*
+ * Take a dillo rc line and return 'name' and 'value' pointers to it.
+ * Notes:
+ *    - line is modified!
+ *    - it skips blank lines and lines starting with '#'
+ *
+ * Return value: 0 on successful value/pair, -1 otherwise
+ */
+int dParser_get_rc_pair(char **line, char **name, char **value)
+{
+   char *eq, *p;
+   int len, ret = -1;
+
+   dReturn_val_if_fail(*line, ret);
+
+   *name = NULL;
+   *value = NULL;
+   dStrstrip(*line);
+   if (*line[0] != '#' && (eq = strchr(*line, '='))) {
+      /* get name */
+      for (p = *line; *p && *p != '=' && !isspace(*p); ++p);
+      *p = 0;
+      *name = *line;
+
+      /* get value */
+      if (p == eq) {
+         for (++p; isspace(*p); ++p);
+         len = strlen(p);
+         if (len >= 2 && *p == '"' && p[len-1] == '"') {
+            p[len-1] = 0;
+            ++p;
+         }
+         *value = p;
+         ret = 0;
+      }
+   }
+
+   return ret;
+}
+
+/*
  *- Misc utility functions ----------------------------------------------------
  */
 
--- a/dlib/dlib.h	Wed Dec 05 16:39:22 2007 +0100
+++ b/dlib/dlib.h	Thu Dec 06 18:12:02 2007 +0100
@@ -144,6 +144,11 @@
 void *dList_find_sorted (Dlist *lp, const void *data, dCompareFunc func);
 
 /*
+ *- Parse function ------------------------------------------------------------
+ */
+int dParser_get_rc_pair(char **line, char **name, char **value);
+
+/*
  *- Misc utility functions ----------------------------------------------------
  */
 char *dGetcwd ();
--- a/dpid/Makefile.am	Wed Dec 05 16:39:22 2007 +0100
+++ b/dpid/Makefile.am	Thu Dec 06 18:12:02 2007 +0100
@@ -24,3 +24,8 @@
 install-data-local :
 	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
 	echo dpi_dir=$(libdir)/dillo/dpi > $(DESTDIR)$(sysconfdir)/dpidrc
+	echo >> $(DESTDIR)$(sysconfdir)/dpidrc
+	echo "proto.file=file/file.dpi" >> $(DESTDIR)$(sysconfdir)/dpidrc
+	echo "proto.ftp=ftp/ftp.filter.dpi" >> $(DESTDIR)$(sysconfdir)/dpidrc
+	echo "proto.https=https/https.filter.dpi" >> $(DESTDIR)$(sysconfdir)/dpidrc
+	echo "proto.data=datauri/datauri.filter.dpi" >> $(DESTDIR)$(sysconfdir)/dpidrc
--- a/dpid/dpid.c	Wed Dec 05 16:39:22 2007 +0100
+++ b/dpid/dpid.c	Thu Dec 06 18:12:02 2007 +0100
@@ -138,6 +138,20 @@
    *dpi_attr_list_ptr = NULL;
 }
 
+/*! Free memory used by the services list
+ */
+void free_services_list(Dlist *s_list)
+{
+   int i = 0;
+   struct service *s;
+
+   for (i=0; i < dList_length(s_list) ; i++) {
+      s = dList_nth_data(s_list, i);
+      dFree(s->name);
+   }
+   dList_free(s_list);
+}
+
 /*! \todo
  * Remove terminator and est_terminator unless we really want to clean up
  * on abnormal exit.
@@ -331,7 +345,7 @@
    DIR *user_dir_stream, *sys_dir_stream;
    char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
    struct dirent *user_dirent, *sys_dirent;
-   int j, st, not_in_user_list;
+   int st;
    int snum, usr_srv_num;
    size_t dp_sz = sizeof(struct dp);
 
@@ -384,19 +398,10 @@
       while ((sys_dirent = readdir(sys_dir_stream)) != NULL) {
          if (sys_dirent->d_name[0] == '.')
            continue;
-         not_in_user_list = 1;
-         for (j = 0; j < usr_srv_num; j++) {
-            if (strcmp(sys_dirent->d_name, (*attlist)[j].id) == 0) {
-               not_in_user_list = 0;
-               break;
-            }
-         }
-         if (not_in_user_list) {
-            *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
-            st=get_dpi_attr(sys_dpidir, sys_dirent->d_name, &(*attlist)[snum]);
-            if (st == 0)
-               snum++;
-         }
+         *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
+         st=get_dpi_attr(sys_dpidir, sys_dirent->d_name, &(*attlist)[snum]);
+         if (st == 0)
+            snum++;
       }
       closedir(sys_dir_stream);
    }
@@ -409,6 +414,112 @@
    return (snum);
 }
 
+/*
+ * Compare two struct service pointers
+ * This function is used for sorting services
+ */
+static int services_alpha_comp(const struct service *s1,
+                               const struct service *s2)
+{
+   return -strcmp(s1->name, s2->name);
+}
+
+/*! Add services reading a dpidrc file                                         
+ * each non empty or commented line has the form                               
+ * service = path_relative_to_dpidir                                           
+ * \Return:                                                                    
+ * \li Returns number of available services on success                         
+ * \li -1 on failure                                                           
+ */                                                                            
+int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list)
+{
+   FILE *dpidrc_stream;
+   char *p, *line = NULL;
+   char *service, *path;
+   int i;
+   struct service *s;
+   char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
+
+   user_dpidir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
+   if (access(user_dpidir, F_OK) == -1) {
+      /* no dpis in user's space */
+      dFree(user_dpidir);
+      user_dpidir = NULL;
+   }
+   dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
+   if (access(dpidrc, F_OK) == -1) {
+      dFree(dpidrc);
+      dpidrc = dStrdup(DPIDRC_SYS);
+      if (access(dpidrc, F_OK) == -1) {
+         dFree(dpidrc);
+         dpidrc = NULL;
+      }
+   }
+   if (!dpidrc || (sys_dpidir = get_dpi_dir(dpidrc)) == NULL)
+      sys_dpidir = NULL;
+
+   if (!user_dpidir && !sys_dpidir) {
+      ERRMSG("fill_services_list", "Fatal error ", 0);
+      MSG_ERR("\n - Can't find the directory for dpis.\n");
+      exit(1);
+   }
+
+   if ((dpidrc_stream = fopen(dpidrc, "r")) == NULL) {
+      ERRMSG("fill_services_list", "popen failed", errno);
+      dFree(dpidrc);
+      dFree(sys_dpidir);
+      dFree(user_dpidir);
+      return (-1);
+   }
+
+   if (*services_list != NULL) {
+      ERRMSG("fill_services_list", "services_list parameter is not NULL", 0);
+      return -1;
+   }
+   *services_list = dList_new(8);
+
+   /* dpidrc parser loop */
+   while ((line = dGetline(dpidrc_stream)) != NULL) {
+
+      if (dParser_get_rc_pair(&line, &service, &path) == -1) {
+         if (line[0] && line[0] != '#' && (!service || !path)) {
+            MSG_ERR("Syntax error in %s: service=\"%s\" path=\"%s\"\n",
+                    dpidrc, service, path);
+         }
+         continue;
+      }
+
+      /* ignore dpi_dir silently */
+      if (strcmp(service, "dpi_dir") == 0)
+         continue;
+
+      s = dNew(struct service, 1);
+      /* init services list entry */
+      s->name = dStrdup(service);
+      s->dp_index = -1;
+
+      dList_append(*services_list, s);
+      /* search the dpi for a service by its path */
+      for (i = 0; i < numdpis; i++)
+          if ((p = strstr(attlist[i].path, path)) && *(p - 1) == '/' &&
+              strlen(p) == strlen(path))
+             break;
+      /* if the dpi exist bind service and dpi */
+      if (i < numdpis)
+         s->dp_index = i;
+      dFree(line);
+   }
+   fclose(dpidrc_stream); 
+
+   dList_sort(*services_list, (dCompareFunc)services_alpha_comp);
+
+   dFree(dpidrc);
+   dFree(sys_dpidir);
+   dFree(user_dpidir);
+
+   return (dList_length(*services_list));
+}
+
 /*! Initialise the service request socket
  * \Return:
  * \li Number of sockets (1 == success)
@@ -496,7 +607,8 @@
    dpi_attr->sa.sun_family = AF_LOCAL;
    dpi_nm = get_basename(dpi_attr->path);
 
-   dpi_attr->sockpath = dStrconcat(sockdir, "/", dpi_nm, NULL);
+   dpi_attr->sockpath = dStrconcat(sockdir, "/", dpi_nm, "-XXXXXX", NULL);
+   mktemp(dpi_attr->sockpath);
    if (strlen(dpi_attr->sockpath) > sp_len) {
       ERRMSG("init_all_dpi_sockets", "socket path is too long", 0);
       MSG_ERR("\n - it should be <= %lu chars", (ulong_t)sp_len);
@@ -668,11 +780,14 @@
    stop_active_dpis(dpi_attr_list, numdpis);
    rm_dpi_sockets(dpi_attr_list, numdpis);
    free_plugin_list(&dpi_attr_list, numdpis);
+   free_services_list(services_list);
+   services_list = NULL;
    numdpis = 0;
    numsocks = 1;                /* the srs socket */
    FD_ZERO(&sock_set);
    FD_SET(srs, &sock_set);
    numdpis = register_all(&dpi_attr_list);
+   fill_services_list(dpi_attr_list, numdpis, &services_list);
    numsocks = init_all_dpi_sockets(dpi_attr_list, sockdir);
    return (numdpis);
 }
@@ -697,6 +812,24 @@
    return (msg);
 }
 
+/*
+ * Compare a struct service pointer and a service name
+ * This function is used for searching services by name
+ */
+int service_match(const struct service *A, const char *B)
+{
+   int A_len, B_len, len;
+
+   A_len = strlen(A->name);
+   B_len = strlen(B);
+   len = MAX (A_len, B_len);
+
+   if (A->name[A_len - 1] == '*')
+      len = A_len - 1;
+
+   return(dStrncasecmp(A->name, B, len));
+}
+
 /*!
  * Send socket path that matches dpi_id to client
  */
@@ -705,12 +838,18 @@
    int i;
    char *dpi_id;
    char *d_cmd;
+   struct service *serv;
 
    dReturn_if_fail((dpi_id = get_message(sock, dpi_tag)) != NULL);
 
-   for (i = 0; i < numdpis; i++)
-      if (strstr(dpi_attr_list[i].id, dpi_id))
-         break;
+   serv = dList_find_custom(services_list,dpi_id,(dCompareFunc)service_match);
+
+   if (serv == NULL || (i = serv->dp_index) == -1)
+      for (i = 0; i < numdpis; i++)
+         if (!strncmp(dpi_attr_list[i].id, dpi_id,
+        dpi_attr_list[i].id - strchr(dpi_attr_list[i].id, '.')))
+            break;
+
    if (i < numdpis) {
       /* found */
       if (access(dpi_attr_list[i].path, F_OK) == -1) {
--- a/dpid/dpid.h	Wed Dec 05 16:39:22 2007 +0100
+++ b/dpid/dpid.h	Thu Dec 06 18:12:02 2007 +0100
@@ -45,6 +45,13 @@
    int filter;
 };
 
+/*! bind dpi with service
+ */
+struct service {
+   char *name;
+   int dp_index;
+};
+
 /*! Number of available plugins */
 int numdpis;
 
@@ -54,6 +61,9 @@
 /*! State information for each plugin. */
 struct dp *dpi_attr_list;
 
+/*! service served for each plugin  */
+Dlist *services_list;
+
 /*! Set of sockets watched for connections */
 fd_set sock_set;
 
@@ -70,6 +80,8 @@
 
 void free_plugin_list(struct dp **dpi_attr_list_ptr, int numdpis);
 
+void free_services_list(Dlist *s_list);
+
 enum file_type get_file_type(char *file_name);
 
 int get_dpi_attr(char *dpi_dir, char *service, struct dp *dpi_attr);
@@ -78,6 +90,8 @@
 
 int register_all(struct dp **attlist);
 
+int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list);
+
 int init_srs_socket(char *sockdir);
 
 int init_dpi_socket(struct dp *dpi_attr, char *sockdir);
@@ -98,6 +112,8 @@
 
 char *get_message(int sock, char *dpi_tag);
 
+int service_match(const struct service *A, const char *B);
+
 void send_sockpath(int sock, char * dpi_tag, struct dp *dpi_attr_list);
 
 #endif
--- a/dpid/main.c	Wed Dec 05 16:39:22 2007 +0100
+++ b/dpid/main.c	Thu Dec 06 18:12:02 2007 +0100
@@ -228,6 +228,7 @@
    fd_set selected_set;
 
    dpi_attr_list = NULL;
+   services_list = NULL;
    //daemon(0,0); /* Use 0,1 for feedback */
    /* todo: call setsid() ?? */
 
@@ -258,6 +259,9 @@
       exit(1);
    }
 
+   /* Init and get services list */
+   fill_services_list(dpi_attr_list, numdpis, &services_list);
+
    /* Remove any sockets that may have been leftover from a crash */
    cleanup(sockdir);
    /* Initialise sockets */
--- a/src/capi.c	Wed Dec 05 16:39:22 2007 +0100
+++ b/src/capi.c	Thu Dec 06 18:12:02 2007 +0100
@@ -240,8 +240,12 @@
 static int Capi_url_uses_dpi(DilloUrl *url, char **server_ptr)
 {
    char *p, *server = NULL, *url_str = URL_STR(url);
+   Dstr *tmp;
 
-   if (dStrncasecmp(url_str, "dpi:/", 5) == 0) {
+   if ((dStrncasecmp(url_str, "http:", 5) == 0) ||
+       (dStrncasecmp(url_str, "about:", 6) == 0)) {
+      /* URL doesn't use dpi (server = NULL) */
+   } else if (dStrncasecmp(url_str, "dpi:/", 5) == 0) {
       /* dpi prefix, get this server's name */
       if ((p = strchr(url_str + 5, '/')) != NULL) {
          server = dStrndup(url_str + 5, (uint_t)(p - url_str - 5));
@@ -252,16 +256,11 @@
          dFree(server);
          server = dStrdup("bookmarks");
       }
-
-   } else if (dStrncasecmp(url_str, "ftp:/", 5) == 0) {
-      server = dStrdup("ftp");
-
-   } else if (dStrncasecmp(url_str, "https:/", 7) == 0) {
-      server = dStrdup("https");
-   } else if (dStrncasecmp(url_str, "file:", 5) == 0) {
-      server = dStrdup("file");
-   } else if (dStrncasecmp(url_str, "data:", 5) == 0) {
-      server = dStrdup("datauri");
+   } else if ((p = strchr(url_str, ':')) != NULL) {
+      tmp = dStr_new("proto.");
+      dStr_append_l(tmp, url_str, p - url_str);
+      server = tmp->str;
+      dStr_free(tmp, 0);
    }
 
    return ((*server_ptr = server) ? 1 : 0);
--- a/src/prefs.c	Wed Dec 05 16:39:22 2007 +0100
+++ b/src/prefs.c	Thu Dec 06 18:12:02 2007 +0100
@@ -109,50 +109,6 @@
 }
 
 /*
- * Take a dillo rc line and return 'name' and 'value' pointers to it.
- * Notes:
- *    - line is modified!
- *    - it skips blank lines and lines starting with '#'
- *
- * Return value: 0 on successful value/pair, -1 otherwise
- */
-static int Prefs_get_pair(char **line, char **name, char **value)
-{
-   char *eq, *p;
-   int len, ret = -1;
-
-   dReturn_val_if_fail(*line, ret);
-
-   *name = NULL;
-   *value = NULL;
-   dStrstrip(*line);
-   if (*line[0] != '#' && (eq = strchr(*line, '='))) {
-      /* get name */
-      for (p = *line; *p && *p != '=' && !isspace(*p); ++p);
-      *p = 0;
-      *name = *line;
-
-      /* get value */
-      if (p == eq) {
-         for (++p; isspace(*p); ++p);
-         len = strlen(p);
-         if (len >= 2 && *p == '"' && p[len-1] == '"') {
-            p[len-1] = 0;
-            ++p;
-         }
-         *value = p;
-         ret = 0;
-      }
-   }
-
-   if (*line[0] && *line[0] != '#' && (!*name || !*value)) {
-      MSG("prefs: Syntax error in %s: name=\"%s\" value=\"%s\"\n",
-          RCNAME, *name, *value);
-   }
-   return ret;
-}
-
-/*
  * Parse a name/value pair and set preferences accordingly.
  */
 static int Prefs_parse_pair(char *name, char *value)
@@ -348,9 +304,12 @@
    if (F_in) {
       /* scan dillorc line by line */
       while ((line = dGetline(F_in)) != NULL) {
-         if (Prefs_get_pair(&line, &name, &value) == 0){
+         if (dParser_get_rc_pair(&line, &name, &value) == 0) {
             _MSG("{%s}, {%s}\n", name, value);
             Prefs_parse_pair(name, value);
+         } else if (line[0] && line[0] != '#' && (!name || !value)) {
+            MSG("prefs: Syntax error in %s: name=\"%s\" value=\"%s\"\n",
+                RCNAME, name, value);
          }
          dFree(line);
       }