/**************************************************************************** mod_dav_pgsql (DASL) for apache 2.X CopyRight(C) 2005 SolutionBox Inc. All Rights reserved. Author : sean kim (sean@solutionbox.co.kr) $Id: props.c,v 1.2 2006/09/20 09:22:59 sean Exp $ Redistribution and use in source and binary forms, with or with out modification, are not permitted in outside of SolutionBox Inc. ****************************************************************************/ /* TODO 1. remove etags filed 2. change collection to int 3. change all time field to long */ #include #include #include #include /* for ap_construct_url */ #include #include #include #include #include "dav_repos.h" #include "dbms.h" #include "util.h" struct dav_namespace_map { int *ns_map; }; struct dav_db { apr_pool_t *pool; dav_repos_resource *mdb_r; /* when used as a property database: */ int version; /* *minor* version of this db */ dav_buffer ns_table; /* table of namespace URIs */ short ns_count; /* number of entries in table */ int ns_table_dirty; /* ns_table was modified */ apr_hash_t *uri_index; dav_buffer wb_key; /* work buffer for dav_key */ apr_datum_t iter; /* iteration key */ }; static dav_error *dav_repos_db_open(apr_pool_t * p, const dav_resource * resource, int ro, dav_db ** pdb) { DBG0("dav_repos_db_open: "); // 2013.08.22 dadamin // µð·ºÅ丮 °æ¿ì À¯ÀÏÇÑ °ªÀ» ÃßÃâÇÒ ¼ö ¾ø¾î¼­ ¼Ó¼º º¯°æ ºÒ°¡´É Çϵµ·ÏÇÔ if(resource && resource->info) { dav_resource_private *ctx = resource->info; if(ctx->db_r) { if(ctx->db_r->m_resource_type) { *pdb = NULL; return NULL; } } } dav_db *db = apr_pcalloc(p, sizeof(*db)); TRACE(); /* Set some values for DB */ db->pool = p; db->mdb_r = (dav_repos_resource *) resource->info->db_r; *pdb = db; db->uri_index = apr_hash_make(p); return NULL; } static void dav_repos_db_close(dav_db * db) { TRACE(); } static dav_error *dav_repos_db_define_namespaces(dav_db * db, dav_xmlns_info * xi) { const char *ns, *xmlns; dav_repos_property *dead_prop; dav_repos_resource *dbr = db->mdb_r; DBG0("dav_repos_db_define_namespaces: "); TRACE(); /* Null lock */ if (dbr == NULL) return NULL; // 2013.08.22 dadamin /* Check all used name space in this resource */ for (dead_prop = dbr->pr; dead_prop; dead_prop = dead_prop->next) { ns = dbms_get_ns(dbr, dead_prop->m_ns_id); if (ns && strlen(ns)) { /* not nullns */ xmlns = apr_psprintf(dbr->p, "ns%ld", dead_prop->m_ns_id); dav_xmlns_add(xi, xmlns, ns); } } /* ### we don't have any other possible namespaces right now. */ return NULL; } static dav_error *dav_repos_db_output_value(dav_db * db, const dav_prop_name * name, dav_xmlns_info * xi, apr_text_header * phdr, int *found) { const char *s = NULL; const char *val; /* Get resource records */ dav_repos_resource *dbr = db->mdb_r; apr_pool_t *pool = db->pool; DBG1("dav_repos_db_output_value: name:%s", name->name); TRACE(); if (dbr == NULL) { *found = 0; return NULL; } DBG2("OUT %s [] %s\n", name->ns, name->name); if (!strcmp(name->ns, "DAV:")) { val = apr_hash_get(dbr->lpr_hash, name->name, APR_HASH_KEY_STRING); if (val) { s = apr_psprintf(pool, "%s" DEBUG_CR, name->name, val, name->name); } // 2014.07.09 : »ç¿ëµÇÁö ¾Ê´Â Ä÷³ Á¤¸®(get_content_language,get_etag,supported_lock,lock_discovery) else if (!strcmp(name->name, "lockdiscovery") ) { s = apr_psprintf(pool, "" DEBUG_CR, name->name, name->name); } else if (!strcmp(name->name, "supportedlock")) { } } DBG2("OUT2 %s [] %s\n", name->ns, name->name); if (s == NULL) { /* Dead props or Not found */ /* Get the key */ const char *key = dav_repos_build_ns_name_key(name->ns, name->name, pool); /* Get the dead prop */ dav_repos_property *dead_prop = apr_hash_get(dbr->pr_hash, key, APR_HASH_KEY_STRING); if (dead_prop != NULL) { /* Null ns */ if (strlen(name->ns) == 0 || !strcmp(name->ns, " ")) { s = apr_psprintf(pool, "<%s xmlns=\"\">%s" DEBUG_CR, name->name, dead_prop->m_propvalue, name->name); } else { /* Not null ns */ s = apr_psprintf(pool, "%s" DEBUG_CR, dead_prop->m_ns_id, name->name, dead_prop->m_propvalue, dead_prop->m_ns_id, name->name); } } else { // 2013.08.27 dadamin // SolDirve PROPFIND ½Ã ³×ÀÓ½ºÆäÀ̽º »ç¿ëÇϱ⠶§¹®¿¡ // ÇØ´ç ÆÄÀÏ(µð·ºÅ丮 °æ¿ì ¼Ò¼ÓµÈ ¸ðµç Á¤º¸)¿¡ ´ëÇØ¼­ // RCDB ³×ÀÓ½ºÆäÀ̽º °ü·Ã Á¶È¸ ¹ß»ýÀ¸·Î ÀÀ´ä ¼º´É ÀúÇϰ¡ // ¹ß»ýÇÔÀ¸·Î opendav ÁöÁ¤µÈ(DAV:)¿Í ±âº» ¼Ó¼ºÀÌ ¿Ü¿¡ °ª¿¡ // ´ëÇØ¼­ ¿ÀÆÛ·¹À̼ǵÇÁö ¾Ê°ÔÇÔ #ifdef __USE_NAMESPACE__ // 2013.08.22 dadamin // t_dav_resource ¾ø´Â property¿¡ ´ëÇØ¼­ Á¶È¸ dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr)); // Let's fill fill pr pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns); pr->m_propname = name->name; if(dbms_get_dead_property(dbr, pr) == 0) { dbr->pr = pr; s = apr_psprintf(pool, "%s" DEBUG_CR, pr->m_ns_id, pr->m_propname, pr->m_propvalue, pr->m_ns_id, pr->m_propname); // set namespace // ÇØ´ç ³×ÀÓ½ºÆäÀ̽º Á¸ÀçÇÏÁö ¾ÊÀ» ½Ã PROPFIND¿¡¼­ // ¿Ã¹Ù¸¥ ³×ÀÓ½ºÆäÀ̽º·Î ¸®ÅϵÇÁö ¾Ê´Â °ÍÀ» ¹æÁöÇϱâ À§Çؼ­ // °ü·Ã ³×ÀÓ½ºÆäÀ̽º¸¦ Ç콬Å×ÀÌºí¿¡ ÀúÀåÇÔ dbms_set_namespace(dbr, pr, name->ns); } else #endif // __USE_NAMESPACE__ { DBG1("NOFPUND [%s]\n", key); } } } if (s) { *found = 1; apr_text_append(pool, phdr, s); } else { *found = 0; } return NULL; } static dav_error *dav_repos_db_map_namespaces(dav_db * db, const apr_array_header_t * namespaces, dav_namespace_map ** mapping) { dav_namespace_map *m = apr_palloc(db->pool, sizeof(*m)); int i; int *pmap; const char **puri; TRACE(); /* ** Iterate over the provided namespaces. If a namespace already appears ** in our internal map of URI -> ns_id, then store that in the map. If ** we don't know the namespace yet, then add it to the map and to our ** table of known namespaces. */ pmap = apr_palloc(db->pool, namespaces->nelts * sizeof(*pmap)); for (i = namespaces->nelts, puri = (const char **) namespaces->elts; i-- > 0; ++puri, ++pmap) { const char *uri = *puri; apr_size_t uri_len = strlen(uri); long ns_id = (long) apr_hash_get(db->uri_index, uri, uri_len); if (ns_id == 0) { dav_check_bufsize(db->pool, &db->ns_table, uri_len + 1); memcpy(db->ns_table.buf + db->ns_table.cur_len, uri, uri_len + 1); db->ns_table.cur_len += uri_len + 1; /* copy the uri in case the passed-in namespaces changes in some way. */ apr_hash_set(db->uri_index, apr_pstrdup(db->pool, uri), uri_len, (void *) ((long)(db->ns_count + 1))); db->ns_table_dirty = 1; *pmap = db->ns_count++; } else { *pmap = ns_id - 1; } } m->ns_map = pmap; *mapping = m; return NULL; } static dav_error *dav_repos_db_store(dav_db * db, const dav_prop_name * name, const apr_xml_elem * elem, dav_namespace_map * mapping) { size_t l_val; #ifdef __OPENDAV_DEBUG__ char *buf; #endif // __OPENDAV_DEBUG__ char *val; dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr)); TRACE(); // 2013.08.27 dadamin // SolDirve PROPFIND ½Ã ³×ÀÓ½ºÆäÀ̽º »ç¿ëÇϱ⠶§¹®¿¡ // ÇØ´ç ÆÄÀÏ(µð·ºÅ丮 °æ¿ì ¼Ò¼ÓµÈ ¸ðµç Á¤º¸)¿¡ ´ëÇØ¼­ // RCDB ³×ÀÓ½ºÆäÀ̽º °ü·Ã Á¶È¸ ¹ß»ýÀ¸·Î ÀÀ´ä ¼º´É ÀúÇϰ¡ // ¹ß»ýÇÔÀ¸·Î opendav ÁöÁ¤µÈ(DAV:)¿Í ±âº» ¼Ó¼ºÀÌ ¿Ü¿¡ °ª¿¡ // ´ëÇØ¼­ ¿ÀÆÛ·¹À̼ǵÇÁö ¾Ê°ÔÇÔ #ifndef __USE_NAMESPACE__ return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0, "Invalid namespace declaration."); #endif // !__USE_NAMESPACE__ /* Litmus test case */ /* if(name->ns==NULL || strlen(name->ns)==0) { return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0, "Invalid namespace declaration."); } */ /* quote all the values in the element */ /* ### be nice to do this without affecting the element itself */ /* ### of course, the cast indicates Badness is occurring here */ apr_xml_quote_elem(db->pool, (apr_xml_elem *) elem); /* generate a text blob for the xml:lang plus the contents */ apr_xml_to_text(db->pool, elem, APR_XML_X2T_LANG_INNER, NULL, mapping->ns_map, (const char **) &val, &l_val); /* Warning : val[0] value is NULL, so you should use 'val+1' */ /* Let's fill fill pr */ pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns); pr->m_propname = name->name; pr->m_propvalue = val + 1; if (dbms_set_dead_property(db->mdb_r, pr) != 0) { return solbox_dav_new_error(db->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "An error occurred while getting a dead property."); } #ifdef __OPENDAV_DEBUG__ buf = apr_psprintf(db->pool, "I want to save [%ld:%s] [%s]", pr->m_ns_id, pr->m_propname, pr->m_propvalue); DBG0(buf); #endif // __OPENDAV_DEBUG__ return NULL; } static dav_error *dav_repos_db_remove(dav_db * db, const dav_prop_name * name) { // 2013.08.27 dadamin // SolDirve PROPFIND ½Ã ³×ÀÓ½ºÆäÀ̽º »ç¿ëÇϱ⠶§¹®¿¡ // ÇØ´ç ÆÄÀÏ(µð·ºÅ丮 °æ¿ì ¼Ò¼ÓµÈ ¸ðµç Á¤º¸)¿¡ ´ëÇØ¼­ // RCDB ³×ÀÓ½ºÆäÀ̽º °ü·Ã Á¶È¸ ¹ß»ýÀ¸·Î ÀÀ´ä ¼º´É ÀúÇϰ¡ // ¹ß»ýÇÔÀ¸·Î opendav ÁöÁ¤µÈ(DAV:)¿Í ±âº» ¼Ó¼ºÀÌ ¿Ü¿¡ °ª¿¡ // ´ëÇØ¼­ ¿ÀÆÛ·¹À̼ǵÇÁö ¾Ê°ÔÇÔ #ifndef __USE_NAMESPACE__ return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0, "Invalid namespace declaration."); #endif // !__USE_NAMESPACE__ #ifdef __OPENDAV_DEBUG__ char *buf; #endif // __OPENDAV_DEBUG__ dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr)); pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns); pr->m_propname = name->name; if (dbms_del_dead_property(db->mdb_r, pr) != 0) { return solbox_dav_new_error(db->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "An error occurred while deleting a dead property."); } TRACE(); #ifdef __OPENDAV_DEBUG__ buf = apr_psprintf(db->pool, "I want to delete [%s] ", pr->m_propname); DBG0(buf); #endif // __OPENDAV_DEBUG__ return NULL; } static int dav_repos_db_exists(dav_db * db, const dav_prop_name * name) { /* Get resource records */ dav_repos_resource *dbr = db->mdb_r; /* Build the key */ const char *key; TRACE(); if (dbr == NULL) return 0; key = dav_repos_build_ns_name_key(name->ns, name->name, dbr->p); /* Get the the prop */ if (apr_hash_get(dbr->pr_hash, key, APR_HASH_KEY_STRING)) return 1; return 0; } static dav_error *dav_repos_db_first_name(dav_db * db, dav_prop_name * pname) { const char *key = NULL; apr_ssize_t klen; dav_repos_property *pr; /* Get resource records */ dav_repos_resource *dbr = db->mdb_r; TRACE(); if (dbr == NULL) { pname->ns = NULL; pname->name = NULL; return NULL; } dbr->pr_hash_index = apr_hash_first(db->pool, dbr->pr_hash); if (dbr->pr_hash_index == NULL) { pname->ns = NULL; pname->name = NULL; return NULL; } apr_hash_this(dbr->pr_hash_index, (void *) &key, &klen, (void *) &pr); /* Get ns and name from the key */ dav_repos_get_ns_name_key(key, pname, db->pool); return NULL; } static dav_error *dav_repos_db_next_name(dav_db * db, dav_prop_name * pname) { const char *key = NULL; apr_ssize_t klen; dav_repos_property *pr; /* Get resource records */ dav_repos_resource *dbr = db->mdb_r; TRACE(); pname->ns = NULL; pname->name = NULL; if (dbr == NULL) { return NULL; } /* Run first_name first */ if (dbr->pr_hash_index == NULL) return NULL; dbr->pr_hash_index = apr_hash_next(dbr->pr_hash_index); /* End of hash */ if (dbr->pr_hash_index == NULL) return NULL; apr_hash_this(dbr->pr_hash_index, (void *) &key, &klen, (void *) &pr); /* Get ns and name from the key */ dav_repos_get_ns_name_key(key, pname, db->pool); return NULL; } static dav_error *dav_repos_db_get_rollback(dav_db * db, const dav_prop_name * name, dav_deadprop_rollback ** prollback) { TRACE(); return NULL; } static dav_error *dav_repos_db_apply_rollback(dav_db * db, dav_deadprop_rollback * rollback) { TRACE(); return NULL; } const dav_hooks_propdb dav_repos_hooks_propdb = { dav_repos_db_open, dav_repos_db_close, dav_repos_db_define_namespaces, dav_repos_db_output_value, dav_repos_db_map_namespaces, dav_repos_db_store, dav_repos_db_remove, dav_repos_db_exists, dav_repos_db_first_name, dav_repos_db_next_name, dav_repos_db_get_rollback, dav_repos_db_apply_rollback, };