--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#undef PUBLIC
+#define PUBLIC EXPORT
+#include <notification.h>
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT n_object* n_object_new(char* s)
+{
+ return 0;
+}
+
+EXPORT void n_commit(n_object* o)
+{
+}
+
+EXPORT n_object* n_see(n_object* o, char* uid)
+{
+ return 0;
+}
+
+EXPORT char* n_to_string(n_object* o)
+{
+ return 0;
+}
+
+EXPORT char* n_uid(n_object* o)
+{
+ return 0;
+}
+
+EXPORT char* n_header(n_object* o, char* name)
+{
+ return 0;
+}
+
+EXPORT k_hashtable* n_headers(n_object* o)
+{
+ return 0;
+}
+
+EXPORT k_hashtable* n_content(n_object* o)
+{
+ return 0;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+static char* hostname;
+static k_hashtable* resources;
+
+/* -}{---- ------------------------------------------------------------------ */
+
+typedef struct ni_driver{
+ char* name;
+ ni_handles_resource handles_resource;
+ ni_sync_resource sync_resource;
+} ni_driver;
+
+/* -}{---- From headers.c --------------------------------------------------- */
+
+extern void init_headers(void);
+extern void drop_entity_headers(k_hashtable* ent_head);
+extern void fill_headers(k_hashtable* ent_head,
+ char* status,
+ char* statustext,
+ char* uri,
+ time_t modifitime,
+ int datalength,
+ char* mimetype,
+ char* encoding,
+ int nocache);
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static void incoming_request(ni_event* evq);
+static ni_resource* ensure_res(char* pub);
+static void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub);
+static void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub);
+static k_hashtable* get_this(k_hashtable*, char*, k_hashtable*);
+static k_hashtable* get_using(k_hashtable* curr, char* tag, char* val);
+static void post_to_driver(char* pub, ni_event* evq);
+static void incoming_resource(ni_event* evt);
+static void test_pub_tos(ni_resource* res, ni_event* evt, int entityok);
+static int satisfiable(k_hashtable*, ni_resource*, ni_event*, int);
+static void update_pubcache(int, k_hashtable**, k_hashtable*, k_hashtable*);
+static int sub_less(k_hashtable* sub1, k_hashtable* sub2);
+static void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh);
+static int sub_ok(k_hashtable* sub);
+static int range_ok(char* range, char* conrange);
+static void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh);
+static void merge_entity_range(ni_resource* res, ni_event* evt);
+static void respond( k_hashtable* sub, ni_resource* res, ni_event* evt);
+static void respond_ok(k_hashtable* sub, ni_event* evv);
+static void respond_nf(k_hashtable* sub, ni_event* evv);
+static void* entity_to_octets(k_hashtable* ent_head, void* entity);
+static char* handled_by(char* pub);
+static void call_sync_resource(ni_resource* res);
+static ni_driver* ni_driver_new(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource);
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT int on_module_loaded(void)
+{
+ resources=k_hashtable_new("Resources", 0);
+
+ init_headers();
+
+ k_log_out("ON initialised");
+ return 1;
+}
+
+EXPORT void on_module_tick(void)
+{
+}
+
+EXPORT int on_module_event(void* data)
+{
+ ni_event* evt=data;
+
+ if(!k_hashtable_get(evt->ent_head, "Status:")){
+
+ incoming_request(evt);
+ }
+ else{
+ incoming_resource(evt);
+ }
+ return 1;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void incoming_request(ni_event* evq)
+{
+ int L=1;
+ if(L) ni_event_show(evq, "ON got request event");
+
+ k_hashtable* sub=evq->ent_head;
+ char* uri =k_hashtable_get(sub, "URI:");
+ char* pub =k_hashtable_get(sub, "Sub-To:"); if(!pub) return;
+ int styor=k_hashtable_isi(sub, "Sub-Type:", "Original");
+ char* via =k_hashtable_get(sub, "Via:");
+ char* from =k_hashtable_get(sub, "From:");
+ if(L) k_log_out("------------------ %s", pub);
+
+ int nocache=k_hashtable_isi(sub, "Cache-Control:", "no-cache");
+ if(nocache){
+ k_hashtable_remove( sub, "Cache-Control:");
+ k_hashtable_set( sub, "If-Modified-Since:", "0");
+ }
+
+ if(!from){
+ ni_resource* ses=k_hashtable_get(resources, uri);
+ if(ses) ensure_sub_entry(ses->ent_head, sub);
+ if(ses) if(L) ni_resource_show(ses, "Subscribing Resource:");
+ if(styor && via){
+ post_to_driver(pub, evq);
+ return;
+ }
+ }
+
+ ni_resource* res=ensure_res(pub);
+ if(L) ni_resource_show(res, "Publishing Resource:");
+
+ k_hashtable* pubcache=0;
+ int sat=satisfiable(sub, res, 0, 0);
+ update_pubcache(sat, &pubcache, res->ent_head, sub);
+ if(sat){
+ if(L) k_log_out("Memory cache hit for %s", pub);
+ respond(k_hashtable_dup(sub), res, 0);
+ ni_event_delete(evq);
+ }
+ else{
+ ensure_pub_entry(res->ent_head, sub);
+ if(L) ni_resource_show(res, "Pending Resource:");
+ if(pubcache){
+ evq->ent_head=pubcache;
+ post_to_driver(pub, evq);
+ k_hashtable_delete(sub);
+ }
+ else{
+ if(L) k_log_out("In-progress Pub-Cache sufficient");
+ ni_event_delete(evq);
+ }
+ }
+}
+
+ni_resource* ensure_res(char* pub)
+{
+ ni_resource* res=k_hashtable_get(resources, pub);
+ if(!res){
+ res=ni_resource_new(pub, k_hashtable_new("resHeaders", 1), 0);
+ k_hashtable_set(resources, pub, res);
+ }
+ return res;
+}
+
+void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub)
+{
+ char* tag="Sub-To:";
+ k_hashtable* sup=get_this(ent_head, tag, sub);
+ if(!sup){
+ k_hashtable* sup=k_hashtable_dup(sub);
+ char* uri=k_hashtable_extract(sup, "Sub-To:");
+ k_hashtable_put( sup, "URI:", uri);
+ k_hashtable_remove( sup, "Sub-Type:");
+ k_hashtable_sub(ent_head, tag, sup);
+ }
+ else{
+ k_hashtable_remove(sup, "Range:");
+ k_hashtable_remove(sup, "Content-Range:");
+ k_hashtable_remove(sup, "Status:");
+ k_hashtable_remove(sup, "Status-Cache:");
+ char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
+ char* via=k_strdup(k_hashtable_get(sub, "Via:"));
+ char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
+ char* rng=k_strdup(k_hashtable_get(sub, "Range:"));
+ if(mth) k_hashtable_put(sup, "Method:", mth);
+ if(via) k_hashtable_put(sup, "Via:", via);
+ if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
+ if(rng) k_hashtable_put(sup, "Range:", rng);
+ }
+}
+
+void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub)
+{
+ char* tag="Pub-To:";
+ k_hashtable* sup=get_this(ent_head, tag, sub);
+ if(!sup){
+ k_hashtable* sup=k_hashtable_dup(sub);
+ k_hashtable_remove(sup, "Sub-To:");
+ k_hashtable_remove(sup, "Sub-Type:");
+ k_hashtable_sub(ent_head, tag, sup);
+ }
+ else {
+ k_hashtable_remove(sup, "Method:");
+ k_hashtable_remove(sup, "If-Modified-Since:");
+ k_hashtable_remove(sup, "Cache-Control:");
+ k_hashtable_remove(sup, "Update:");
+ char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
+ char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
+ char* ccn=k_strdup(k_hashtable_get(sub, "Cache-Control:"));
+ char* upd=k_strdup(k_hashtable_get(sub, "Update:"));
+ if(mth) k_hashtable_put(sup, "Method:", mth);
+ if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
+ if(ccn) k_hashtable_put(sup, "Cache-Control:", ccn);
+ if(upd) k_hashtable_put(sup, "Update:", upd);
+ }
+}
+
+k_hashtable* get_this(k_hashtable* ent_head, char* pubsub, k_hashtable* try)
+{
+ k_hashtable* curr=k_hashtable_get(ent_head, pubsub);
+ if(!curr) return 0;
+
+ char* tag;
+ char* val;
+
+ tag="From:";
+ val=k_hashtable_get(try, tag);
+ if(val) return get_using(curr, tag, val);
+
+ tag="URI:";
+ val=k_hashtable_get(try, tag);
+ if(val) return get_using(curr, tag, val);
+
+ return 0;
+}
+
+k_hashtable* get_using(k_hashtable* curr, char* tag, char* val)
+{
+ k_hashtable* c;
+ for(c=curr; c; c=c->next) if(k_hashtable_is(c, tag, val)) return c;
+ return c;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void incoming_resource(ni_event* evt)
+{
+ int L=0;
+ if(L) ni_event_show(evt, "ON got resource incoming event");
+
+ ni_resource* res=k_hashtable_get(resources, evt->uri);
+ int fullconst=res && k_hashtable_is(res->ent_head, "Status:", "200") &&
+ k_hashtable_is(res->ent_head, "CUX:", "C");
+
+ if(fullconst){
+ k_log_err("Resource is complete and Constant");
+ ni_event_delete(evt);
+ return;
+ }
+ if(!res) res=ensure_res(evt->uri);
+
+ k_hashtable* reseh=res->ent_head;
+ k_hashtable* evteh=evt->ent_head;
+ int okfull =k_hashtable_is(evteh, "Status:", "200");
+ int partial =k_hashtable_is(evteh, "Status:", "206");
+ int headonly=k_hashtable_is(evteh, "Status:", "260");/*
+ int updated =k_hashtable_is(evteh, "Status:", "266");*/
+ int notmod =k_hashtable_is(evteh, "Status:", "304");
+ int notfound=k_hashtable_is(evteh, "Status:", "404");
+
+ int entityok= (okfull || partial || notmod);
+ int entityev=!(headonly || notmod || notfound);
+ int entityin=!!evt->entity;
+ int entityon=!!res->entity;
+
+ if(!entityev){
+ }
+ if(okfull || !entityon){
+ k_hashtable_merge(reseh, evteh);
+ if(okfull) k_hashtable_remove(reseh, "Content-Range:");
+ }
+ else{
+ merge_non_entity_headers(reseh, evteh);
+ }
+
+ fix_via_subs(evteh, reseh);
+
+ if(entityin){
+ if(okfull || (partial && !entityon)){
+ if(res->entity!=evt->entity){
+ if(!k_hashtable_is(reseh, "CUX:", "C")){
+ k_free(res->entity);
+ }
+ res->entity=evt->entity;
+ }
+ }
+ else
+ if(partial && entityon){
+ merge_entity_range(res, evt);
+ }
+ }
+
+ if(L) ni_resource_show(res, "updated resource - sync and try pubs:");
+
+ call_sync_resource(res);
+
+ test_pub_tos(res, evt, entityok);
+
+ evt->entity=0;
+ ni_event_delete(evt);
+
+ if(L) ni_resource_show(res, "resource after ON:");
+}
+
+void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh)
+{
+ char* from=k_hashtable_get(evteh, "From:");
+ if(!from) return;
+ k_hashtable* subs=k_hashtable_get(reseh, "Sub-To:");
+ k_hashtable* sub;
+ for(sub=subs; sub; sub=sub->next){
+ if(!k_hashtable_is(sub, "Via:", from)) continue;
+ int st=k_hashtable_get_int(evteh, "Status:");
+ char* cr=k_hashtable_get_dup(evteh, "Content-Range:");
+ if(st!=304) k_hashtable_put_int(sub, "Status:", st);
+ if(st==200) k_hashtable_remove( sub, "Content-Range:");
+ else
+ if(cr) k_hashtable_put(sub, "Content-Range:", cr);
+ if(sub_ok(sub)) k_hashtable_set(sub, "Status-Cache:", "OK");
+ }
+}
+
+void test_pub_tos(ni_resource* res, ni_event* evt, int entityok)
+{
+ k_hashtable* keeps=0;
+ k_hashtable* sub=k_hashtable_extract(res->ent_head, "Pub-To:");
+ while(sub){
+ k_hashtable* subnext=sub->next;
+ sub->next=0;
+ int keep=1;
+ int sat=satisfiable(sub, res, evt, entityok);
+ update_pubcache(sat, 0, res->ent_head, sub);
+ if(sat){
+ respond(k_hashtable_dup(sub), res, evt);
+ if(!k_hashtable_get(sub, "Update:")) keep=0;
+ }
+ if(keep){
+ sub->next=keeps;
+ keeps=sub;
+ }
+ else{
+ k_hashtable_delete(sub);
+ }
+ sub=subnext;
+ }
+ sub=keeps;
+ while(sub){
+ k_hashtable* subnext=sub->next;
+ k_hashtable_sub(res->ent_head, "Pub-To:", sub);
+ sub=subnext;
+ }
+}
+
+int satisfiable(k_hashtable* sub,
+ ni_resource* res,
+ ni_event* evt,
+ int entityok)
+{
+ int L=0;
+ int get =k_hashtable_is( sub, "Method:", "GET");
+ int head =k_hashtable_is( sub, "Method:", "HEAD");
+ int dosub=k_hashtable_is( sub, "Method:", "SUB");
+ int unsub=k_hashtable_is( sub, "Method:", "UNSUB");
+ int full=!k_hashtable_isi(sub, "Cache-Control:", "no-full");
+ int updt =k_hashtable_isi(sub, "Update:", "changes");
+ char* ims =k_hashtable_get(sub, "If-Modified-Since:");
+ char* range=k_hashtable_get(sub, "Range:");
+
+ int getsub =get || dosub;
+ int getrange=getsub && range;
+
+ k_hashtable* reseh=res->ent_head;
+ int gotall= k_hashtable_is( reseh, "Status:", "200");
+ int gotrange= k_hashtable_is( reseh, "Status:", "206");
+ int gothead= k_hashtable_is( reseh, "Status:", "260");
+ int gotupdated=evt &&
+ k_hashtable_is(evt->ent_head, "Status:", "266");
+ int notfound= k_hashtable_is( reseh, "Status:", "404");
+ int constant= k_hashtable_is( reseh, "CUX:", "C" );
+ char* conrange= k_hashtable_get(reseh, "Content-Range:");
+
+ if(unsub) return 0;
+ if(notfound) return 1;
+
+ int gotany=(gothead || gotrange || gotall);
+ int snapok=(constant || !ims || entityok);
+
+ int sat=
+ (full &&
+ ((getsub && gotall && snapok) ||
+ (getrange && gotrange && range_ok(range, conrange) && snapok) ||
+ (head && gotany ) ))
+ ||
+ (updt &&
+ ((dosub && gotupdated)));
+
+ if(L) k_log_out("satisfiable %d", sat);
+ return sat;
+}
+
+void update_pubcache(int sat,
+ k_hashtable** pubcachep,
+ k_hashtable* reseh,
+ k_hashtable* sub)
+{
+ if(!sat){ if(pubcachep){
+ k_hashtable* pubcache;
+ pubcache=k_hashtable_get(reseh, "Pub-Cache:");
+ if(!pubcache || sub_less(pubcache, sub)){
+ if(!pubcache){
+ pubcache=k_hashtable_dup(sub);
+ k_hashtable_sub(reseh, "Pub-Cache:", pubcache);
+ }
+ else{
+ k_hashtable_merge(pubcache, sub);
+ }
+ k_hashtable_remove(pubcache, "URI:");
+ k_hashtable_remove(pubcache, "Sub-Type:");
+ *pubcachep=k_hashtable_dup(pubcache);
+ k_hashtable_set(*pubcachep, "Sub-Type:", "Cache");
+ }
+ }}
+ else{ if(!pubcachep){
+ k_hashtable* pubcache;
+ pubcache=k_hashtable_get(reseh, "Pub-Cache:");
+ if(!sub_less(sub, pubcache)){
+ k_hashtable_remove(pubcache, "Method:");
+ k_hashtable_remove(pubcache, "If-Modified-Since:");
+ }
+ }}
+}
+
+int sub_ok(k_hashtable* sub)
+{
+ char* gotresp =k_hashtable_get(sub, "Status:");
+ if(!gotresp) return 0;
+ int notfound=k_hashtable_is( sub, "Status:", "404");
+ if(notfound) return 0;
+ int gotall =k_hashtable_is( sub, "Status:", "200");
+ int gotrange=k_hashtable_is( sub, "Status:", "206");
+ int gothead= k_hashtable_is( sub, "Status:", "260");
+ int doget =k_hashtable_is( sub, "Method:", "GET");
+ int dohead =k_hashtable_is( sub, "Method:", "HEAD");
+ int dosub =k_hashtable_is( sub, "Method:", "SUB");
+ char* range =k_hashtable_get(sub, "Range:");
+ char* conrange=k_hashtable_get(sub, "Content-Range:");
+
+ int dogetsub=doget || dosub;
+ int dogetrange=dogetsub && range;
+ int gotany =(gothead || gotrange || gotall);
+
+ return (dogetsub && gotall ) ||
+ (dogetrange && gotrange && range_ok(range, conrange)) ||
+ (dohead && gotany );
+}
+
+int sub_less(k_hashtable* sub1, k_hashtable* sub2)
+{
+ int L=0;
+ if(L) k_log_out("sub_less sub1:");
+ if(L) k_hashtable_show_chars(sub1);
+ if(L) k_log_out("sub_less sub2:");
+ if(L) k_hashtable_show_chars(sub2);
+ char* mth1 =k_hashtable_get(sub1, "Method:");
+ int head1=k_hashtable_is( sub1, "Method:", "HEAD");
+ int get2 =k_hashtable_is( sub2, "Method:", "GET");
+ char* ims1 =k_hashtable_get(sub1, "If-Modified-Since:");
+ char* ims2 =k_hashtable_get(sub2, "If-Modified-Since:");
+ int full=!k_hashtable_isi(sub2, "Cache-Control:", "no-full");
+ return full && ((!mth1) || (head1 && get2) || (!ims1 && ims2));
+}
+
+int range_ok(char* range, char* conrange)
+{
+ k_log_out("range_ok not implemented: %s vs %s", range, conrange);
+ return 0;
+}
+
+void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh)
+{
+}
+
+void merge_entity_range(ni_resource* res, ni_event* evt)
+{
+ k_log_out("merge_entity_range not implemented yet");
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void respond(k_hashtable* sub, ni_resource* res, ni_event* evt)
+{
+ int updated=evt && k_hashtable_is(evt->ent_head, "Status:", "266");
+ ni_event* evv=updated? ni_event_dup(evt):
+ ni_res_to_evt(res);
+ int L=0;
+ if(L) ni_event_show(evv, "respond");
+
+ k_hashtable_remove(evv->ent_head, "Permit:");
+ k_hashtable_remove(evv->ent_head, "Sub-To:");
+ k_hashtable_remove(evv->ent_head, "Pub-To:");
+ k_hashtable_remove(evv->ent_head, "Pub-Cache:");
+ k_hashtable_sub( evv->ent_head, "Pub-To:", sub);
+
+ int nf;
+ nf=k_hashtable_is( evv->ent_head, "Status:", "404");
+ if(!nf) respond_ok(sub, evv);
+ else respond_nf(sub, evv);
+}
+
+void respond_ok(k_hashtable* sub, ni_event* evv)
+{
+ char* status=0;
+ char* statustext=0;
+ int datalength= -1;
+ int nocache=0;
+ k_hashtable* ent_head=evv->ent_head;
+
+ time_t modifitime=k_hashtable_get_int(ent_head, "Last-Modified-Epoch:");
+ char* modistring=k_hashtable_get( ent_head, "Last-Modified:");
+ if(!modifitime){
+ modifitime=k_time_from_rfc(modistring);
+ }
+ char* imss=k_hashtable_get(sub, "If-Modified-Since:");
+ time_t imst=k_time_from_rfc(imss);
+
+ if(modifitime== -1 || imst== -1 || modifitime > imst){
+ if(k_hashtable_is(sub, "Method:", "HEAD")){
+ evv->entity=0;
+ }
+ if(!k_hashtable_is(ent_head, "CUX:", "C")){
+ evv->entity=entity_to_octets(ent_head, evv->entity);
+ nocache=1;
+ }
+ }
+ else{
+ status="304";
+ statustext="Not Modified";
+ modifitime= -1;
+ nocache= -1;
+ evv->entity=0;
+ drop_entity_headers(ent_head);
+ }
+
+ fill_headers(ent_head, status, statustext, 0,
+ modistring? -1: modifitime,
+ datalength, 0, 0, nocache);
+
+ char* pub =k_hashtable_get(sub, "URI:");
+ int L=0;
+ if(L) ni_event_show(evv, "respond_ok");
+ post_to_driver(pub, evv);
+}
+
+void respond_nf(k_hashtable* sub, ni_event* evv)
+{
+ fill_headers(evv->ent_head, "404", "File Not Found", 0, -1, 0, 0, 0, 1);
+ char* pub =k_hashtable_get(sub, "URI:");
+ post_to_driver(pub, evv);
+}
+
+void post_to_driver(char* pub, ni_event* evq)
+{
+ char* driver=handled_by(pub);
+ if(0) k_log_out("Passing %s on to %s", pub, driver);
+ if(0) ni_event_show(evq, "Post to Driver:");
+ k_event_post(driver, evq);
+}
+
+void* entity_to_octets(k_hashtable* ent_head, void* entity)
+{
+ if(!entity) return 0;
+ size_t size=k_hashtable_get_int(ent_head, "Content-Length:");
+ return k_memdup(entity, size);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT char* ni_hostname()
+{
+ return hostname? hostname: "not set";
+}
+
+EXPORT void ni_hostname_set(char* name)
+{
+ k_free(hostname);
+ hostname=k_strdup(name);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static ni_driver* opdriver;
+static ni_driver* moddriver;
+
+char* handled_by(char* pub)
+{
+ if(moddriver->handles_resource(pub)) return moddriver->name;
+ return "op";
+}
+
+void call_sync_resource(ni_resource* res)
+{
+ if(moddriver->handles_resource(res->uri)) moddriver->sync_resource(res);
+ else opdriver->sync_resource(res);
+}
+
+ni_driver* ni_driver_new(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource)
+{
+ ni_driver* driver=k_malloc(sizeof(ni_driver));
+ driver->name =name;
+ driver->handles_resource=handles_resource;
+ driver->sync_resource =sync_resource;
+ return driver;
+}
+
+EXPORT void ni_register_driver(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource)
+{
+ ni_driver* d=ni_driver_new(name, handles_resource, sync_resource);
+ if(!strcmp(name, "op")) opdriver=d;
+ else moddriver=d;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_resource* ni_resource_new(char* uri,
+ k_hashtable* ent_head,
+ char* entity)
+{
+ char* urih=k_hashtable_get(ent_head, "URI:");
+ if(urih) uri=urih;
+ else
+ if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
+
+ ni_resource* res=k_malloc(sizeof(ni_resource));
+ res->uri =(uri? k_strdup(uri): 0);
+ res->ent_head=ent_head;
+ res->entity =entity;
+ return res;
+}
+
+EXPORT ni_resource* ni_resource_dup(ni_resource* res)
+{
+ ni_resource* rep=k_malloc(sizeof(ni_resource));
+ rep->uri =k_strdup( res->uri);
+ rep->ent_head=k_hashtable_dup(res->ent_head);
+ rep->entity = res->entity;
+ return rep;
+}
+
+EXPORT void ni_resource_delete(ni_resource* res)
+{
+ if(!res) return;
+ if(res->entity && res->ent_head){
+ int constant=k_hashtable_is(res->ent_head, "CUX:", "C");
+ if(!constant) k_free(res->entity);
+ }
+ k_hashtable_delete(res->ent_head);
+ k_free( res->uri);
+ k_free( res);
+}
+
+static char* excto[]={ "Permit:", "Sub-To:", "Pub-To:", 0 };
+static char* perto[]={ "Permit:", 0 };
+static char* subto[]={ "Sub-To:", 0 };
+static char* pubto[]={ "Pub-To:", 0 };
+
+EXPORT void ni_resource_show(ni_resource* res, char* text)
+{
+ if(!res){
+ k_log_out("\n---%s--------\n------------\n\n----------",
+ text);
+ }
+ else{
+ char* b=tmpbuf;
+ size_t s=TMPBUFSIZE;
+ size_t l=0;
+ l+=k_hashtable_snprintf_x(res->ent_head, b+l, s-l, excto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, perto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, subto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, pubto);
+ k_log_out("\n---%s----%s--\n%s----------\n%p\n----------",
+ text, res->uri, tmpbuf, res->entity);
+ }
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_resource* ni_resource_get(char* uri)
+{
+ return k_hashtable_get(resources, uri);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_event* ni_res_to_evt(ni_resource* res)
+{
+ ni_event* evp=k_malloc(sizeof(ni_event));
+ evp->uri =k_strdup( res->uri);
+ evp->evt_head=k_hashtable_new("vHeaders/ni_res_to_evt", 1);
+ evp->ent_head=k_hashtable_dup(res->ent_head);
+ evp->entity = res->entity;
+ return evp;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_event* ni_event_new(char* uri,
+ k_hashtable* evt_head,
+ k_hashtable* ent_head,
+ char* entity)
+{
+ char* urih=k_hashtable_get(ent_head, "URI:");
+ if(urih) uri=urih;
+ else
+ if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
+
+ ni_event* evt=k_malloc(sizeof(ni_event));
+ evt->uri =(uri? k_strdup(uri): 0);
+ evt->evt_head=evt_head;
+ evt->ent_head=ent_head;
+ evt->entity =entity;
+ return evt;
+}
+
+EXPORT ni_event* ni_event_dup(ni_event* evt)
+{
+ ni_event* evp=k_malloc(sizeof(ni_event));
+ evp->uri =k_strdup( evt->uri);
+ evp->evt_head=k_hashtable_dup(evt->evt_head);
+ evp->ent_head=k_hashtable_dup(evt->ent_head);
+ evp->entity = evt->entity;
+ return evp;
+}
+
+EXPORT void ni_event_delete(ni_event* evt)
+{
+ if(!evt) return;
+ if(evt->entity && evt->ent_head){
+ int constant=k_hashtable_is(evt->ent_head, "CUX:", "C");
+ if(!constant) k_free(evt->entity);
+ }
+ k_hashtable_delete(evt->evt_head);
+ k_hashtable_delete(evt->ent_head);
+ k_free( evt->uri);
+ k_free( evt);
+}
+
+EXPORT void ni_event_show(ni_event* evt, char* text)
+{
+ if(!evt){
+ k_log_out("\n---%s--------\n------------\n\n----------",
+ text);
+ }
+ else{
+ char* buf=tmpbuf;
+ int siz=TMPBUFSIZE;
+ int n=k_hashtable_snprintf(evt->evt_head, buf, siz)+1;
+ ; k_hashtable_snprintf(evt->ent_head, buf+n, siz-n);
+ k_log_out("\n---%s----%s--\n"
+ "%s----------\n"
+ "%s----------\n"
+ "%p\n----------",
+ text, evt->uri, buf, buf+n, evt->entity);
+ }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+
+
+