#include #include #include #include #include #include "xmlns.h" module AP_MODULE_DECLARE_DATA annot_view_module ; #define ANNOT_EDITOR 0x01 #define ANNOT_OWNER 0x02 #define ANNOT_ANNOT 0x04 #define ANNOT_LOCKED 0x08 apr_bucket* util_file_bucket(request_rec* r, const char* fname) ; typedef struct { unsigned int status ; time_t timestamp ; unsigned int divid ; unsigned int annotid ; const char* owner ; } annot_parse_ctx ; const xml_char_t* (*xmlns_get_attr_name)(const xmlns_attr_t* attrs, int attnum); const xml_char_t* (*xmlns_get_attr_val)(const xmlns_attr_t* attrs, int attnum); static void xmlns_funcs(void) { xmlns_get_attr_name = APR_RETRIEVE_OPTIONAL_FN(mod_xmlns_get_attr_name); xmlns_get_attr_val = APR_RETRIEVE_OPTIONAL_FN(mod_xmlns_get_attr_val); } #define xmlns_get_appdata(ctx,mod) \ ap_get_module_config((ctx)->f->r->request_config, (mod)) #define xmlns_set_appdata(ctx,mod,x) \ ap_set_module_config((ctx)->f->r->request_config, (mod), (x)) static const xml_char_t* attval(const xmlns_attr_t* atts, const char* key) { int i ; const xml_char_t* k ; for ( i = 0 ; ; ++i ) { k = xmlns_get_attr_name(atts, i) ; if ( ! k ) break ; if ( !strcmp(k, key) ) return xmlns_get_attr_val(atts, i) ; } return NULL ; } static time_t parsedate(const char* sdate) { const xml_char_t* p ; time_t t = 0 ; if ( sdate ) for ( p = sdate; *p; ++p) t = 10*t + (*p - '0') ; return t ; } static void set_locked(xmlns_public* ctx, const xmlns_attr_t* atts) { annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; const xml_char_t* locked = attval(atts, "locked") ; if ( strcasecmp(locked, "Yes") ) pctx->status &= ( ANNOT_LOCKED ^ -1 ) ; else pctx->status |= ANNOT_LOCKED ; } static void set_protection(xmlns_public* ctx, const xmlns_attr_t* atts) { annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; const char* annot = attval(atts, "annot") ; const char* edit = attval(atts, "edit") ; if ( ctx->f->r->user ) { if ( !annot || strcasecmp ( annot, "No") ) pctx->status |= ANNOT_ANNOT ; } else { if ( annot && !strcasecmp ( annot, "Yes") ) pctx->status |= ANNOT_ANNOT ; } if ( edit && !strcasecmp ( edit, "Yes") ) pctx->status |= ANNOT_EDITOR ; } static void add_editor(xmlns_public* ctx, const xmlns_attr_t* atts) { const xml_char_t* login = attval(atts, "login") ; const xml_char_t* user = ctx->f->r->user ; const xml_char_t* owner = attval(atts, "owner") ; annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; if ( login && user && !strcmp(login, user) ) { pctx->status |= (ANNOT_EDITOR|ANNOT_ANNOT) ; if ( owner ) { pctx->status |= ANNOT_OWNER ; } } if ( owner ) { pctx->owner = apr_pstrdup(ctx->f->r->pool, owner) ; } } static void end_annot(xmlns_public* ctx) { ap_fputs(ctx->f->next, ctx->bb, "

") ; } static void start_annot(xmlns_public* ctx, const xmlns_attr_t* atts) { char buf[32] ; annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; const xml_char_t* who = attval(atts, "who") ; const xml_char_t* when = attval(atts, "when") ; time_t t = parsedate(when) ; const char* isnew = ( t > pctx->timestamp ) ? "newannot" : "oldannot" ; const char* tm = ctime_r(&t, buf) ; ++pctx->annotid ; ap_fprintf(ctx->f->next, ctx->bb, "" "
" "

Note by %s, %s

", isnew, pctx->annotid, isnew, pctx->annotid, who, tm , isnew, pctx->annotid, /*who,*/ who, tm ) ; } static void start_abstract(xmlns_public* ctx, const xmlns_attr_t* atts) { ap_fputs(ctx->f->next, ctx->bb, "

") ; } static void start_content(xmlns_public* ctx, const xmlns_attr_t* atts) { annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; ap_fprintf(ctx->f->next, ctx->bb, "
", pctx->divid) ; } static void start_section(xmlns_public* ctx, const xmlns_attr_t* atts) { annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; const xml_char_t* title = attval(atts, "title") ; const xml_char_t* level = attval(atts, "level") ; const xml_char_t* sdate = attval(atts, "when") ; if ( sdate && *sdate ) pctx->timestamp = parsedate(sdate) ; ++pctx->divid ; ap_fprintf(ctx->f->next, ctx->bb, "
", pctx->divid ) ; if ( ! (pctx->status & ANNOT_LOCKED) ) { if ( pctx->status & ANNOT_ANNOT ) { ap_fprintf(ctx->f->next, ctx->bb, "" "\"Add" , ctx->f->r->uri, sdate, pctx->divid) ; } if ( pctx->status & ANNOT_EDITOR ) { ap_fprintf(ctx->f->next, ctx->bb, "" "\"Edit" , ctx->f->r->uri, sdate, pctx->divid) ; } } ap_fprintf(ctx->f->next, ctx->bb, "%s
", level, title, level) ; } static void end_section(xmlns_public* ctx) { ap_fputs(ctx->f->next, ctx->bb, "
") ; } static void end_article(xmlns_public* ctx) { const char* buf ; char mtime[APR_CTIME_LEN] ; annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; apr_ctime(mtime, ctx->f->r->finfo.mtime) ; buf = apr_psprintf(ctx->f->r->pool, "
" "
" "

Owner %s, Last Updated: %s.

" "" "\"Powered" "
" , pctx->owner, mtime) ; ap_fputs(ctx->f->next, ctx->bb, buf) ; ap_fputs(ctx->f->next, ctx->bb, "" ) ; } static void page_template(xmlns_public* ctx, const xmlns_attr_t* atts) { const xml_char_t* title = attval(atts, "title") ; const char* path = ctx->f->r->uri ; const char* component ; char* slash ; ap_fputs(ctx->f->next, ctx->bb, "\n\"Home\"" "\n
" ) ; for ( component = path ; component ; component = slash ) { if ( slash = strchr(component+1, '/'), slash ) { if ( !strncmp(component, "/auth/", 6 ) ) continue ; ap_fputs(ctx->f->next, ctx->bb, "f->next, ctx->bb , path, slash-path+1) ; ap_fputs(ctx->f->next, ctx->bb, "\">") ; ap_fwrite(ctx->f->next, ctx->bb , component+1, slash-(component+1)) ; ap_fputs(ctx->f->next, ctx->bb, " | ") ; } else { ap_fputs(ctx->f->next, ctx->bb, component+1) ; } } ap_fputstrs(ctx->f->next, ctx->bb, "

", title, "

", NULL) ; } static void start_article(xmlns_public* ctx, const xmlns_attr_t* atts) { annot_parse_ctx* pctx = xmlns_get_appdata(ctx, &annot_view_module) ; const char* user = ctx->f->r->user ; const char* anon ; const char* annot = "No" ; const char* edit = "No" ; const char* manage = "No" ; if ( pctx->status & ANNOT_LOCKED ) { ap_fputs(ctx->f->next, ctx->bb, "
" "

Document is currently locked by its owner" " and cannot be annotated or edited. This is a temporary" " condition: please revisit later.

") ; page_template(ctx, atts) ; ap_fputs(ctx->f->next, ctx->bb, "
") ; return ; } if ( pctx->status & ANNOT_ANNOT ) annot = "Yes" ; if ( pctx->status & ANNOT_EDITOR ) edit = "Yes" ; if ( user ) { anon = "" ; if ( pctx->status & ANNOT_OWNER ) manage = "Yes" ; } else { user = "anonymous" ; anon = apr_psprintf(ctx->f->r->pool, "\"Login\"", ctx->f->r->uri) ; } ap_fprintf(ctx->f->next, ctx->bb, "
" "" "" "" "" "" "" "
Privileges for %s
ReadYes
Annotate%s
Edit%s
Manage%s
%s" "\"Help\"", user, annot, edit, manage, anon ) ; page_template(ctx, atts) ; } typedef struct { const char* name ; void (*start)(xmlns_public* ctx, const xmlns_attr_t* atts) ; void (*end)(xmlns_public* ctx) ; } handler_t ; #define end_abstract end_section #define end_content end_section static const handler_t* lookup_handler(const parsedname* name) { static const handler_t handlers[] = { { "section" , start_section, end_section } , { "annot" , start_annot, end_annot } , { "article" , start_article, end_article } , { "content" , start_content, end_content } , { "abstract" , start_abstract, end_abstract } , { "protection" , set_protection, NULL } , { "editor" , add_editor, NULL } , { "lock" , set_locked, NULL } , { NULL , NULL , NULL } } ; const handler_t* h ; for ( h = handlers ; h->name ; ++h ) if ( ! strncmp(h->name, name->elt, name->eltlen) ) return h ; return NULL ; } static int astart(xmlns_public* ctx, const parsedname* name3, const xmlns_attr_t* atts) { const handler_t* handler = lookup_handler(name3) ; if ( handler && handler->start ) handler->start(ctx, atts) ; return OK ; } static int aend(xmlns_public* ctx, const parsedname* name3) { const handler_t* handler = lookup_handler(name3) ; if ( handler && handler->end ) handler->end(ctx) ; return OK ; } static void anamespace(xmlns_public* ctx, const xml_char_t* prefix, const xml_char_t* uri) { annot_parse_ctx* x = apr_pcalloc(ctx->f->r->pool, sizeof(annot_parse_ctx)) ; xmlns_set_appdata(ctx, &annot_view_module, x) ; } static const xmlns xmlns_annot = { XMLNS_VERSION, astart , aend , anamespace , NULL , NULL , NULL , NULL , NULL } ; static void annot_view_hooks(apr_pool_t* p) { ap_register_provider(p, "xmlns", "http://apache.webthing.com/annot", "0", &xmlns_annot) ; ap_hook_optional_fn_retrieve(xmlns_funcs, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA annot_view_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, annot_view_hooks } ;