Big renaming
authoruser <moby@cilux.org>
Thu, 19 Mar 2009 21:17:39 +0000 (21:17 +0000)
committeruser <moby@cilux.org>
Thu, 19 Mar 2009 21:17:39 +0000 (21:17 +0000)
18 files changed:
makefile
src/drivers/np/cache.c [deleted file]
src/drivers/np/np.c [deleted file]
src/drivers/np/uri2chan.c [deleted file]
src/drivers/nt/mid/mid.c [deleted file]
src/drivers/nt/test/testni.c [deleted file]
src/drivers/op/cache.c [new file with mode: 0644]
src/drivers/op/protocol.c [new file with mode: 0644]
src/drivers/op/uri2chan.c [new file with mode: 0644]
src/drivers/ot/mid/mid.c [new file with mode: 0644]
src/drivers/ot/test/teston.c [new file with mode: 0644]
src/include/ni.h [deleted file]
src/include/notification.h [new file with mode: 0644]
src/ni/headers.c [deleted file]
src/ni/ni.c [deleted file]
src/on/headers.c [new file with mode: 0644]
src/on/notification.c [new file with mode: 0644]
src/platform/kernelapi.c

index b972b60..271ab7f 100644 (file)
--- a/makefile
+++ b/makefile
@@ -19,7 +19,7 @@ linux: INCLUDES=-I/usr/local/include -I. -I../include -I../../include -I../../..
 linux: LIBRARIES=-L/usr/local/lib -lnsl -ldl -lm -lX11 -lEGL -lGLESv2
 linux: linux-all
 
-linux-all: cilux mod-ni.so mod-np.so mod-mid.so mod-testni.so install-lin
+linux-all: cilux mod-on.so mod-op.so mod-mid.so mod-teston.so install-lin
 
 # ---------------------------------------------------------------------------- #
 
@@ -31,7 +31,7 @@ version-lin:
        @echo -n " Linux (Built "                      >> src/platform/linux/version.h
        @date | tr '\012' ')'                          >> src/platform/linux/version.h
        @echo "\";"                                    >> src/platform/linux/version.h
-       @echo "static char* cilux_ciux=\"np\";"        >> src/platform/linux/version.h
+       @echo "static char* cilux_ciux=\"op\";"        >> src/platform/linux/version.h
 
 cilux: version-lin src/platform/linux/cilux.c src/platform/linux/kernelplat.h src/platform/linux/kernelplat.c src/platform/kernelapi.c src/include/kernelapi.h src/platform/linux/platform.h
        (cd src/platform/linux; $(CC) $(CCOPTIONS) -c cilux.c -o cilux.o $(COMPILEOPTIONS) $(INCLUDES))
@@ -40,40 +40,40 @@ cilux: version-lin src/platform/linux/cilux.c src/platform/linux/kernelplat.h sr
        $(STRIP) cilux
        @echo '--------------------'
 
-mod-ni.so: src/ni/ni.c src/ni/headers.c src/include/ni.h src/include/kernelapi.h src/platform/linux/platform.h
-       (cd src/ni; $(CC) $(CCOPTIONS) -c headers.c -o headers.o $(COMPILEOPTIONS) $(INCLUDES))
-       (cd src/ni; $(CC) $(CCOPTIONS) -c ni.c     -o ni.o     $(COMPILEOPTIONS) $(INCLUDES))
-       $(CCLIB),mod-ni.so -o mod-ni.so src/ni/headers.o src/ni/ni.o
-       $(STRIP) mod-ni.so
+mod-on.so: src/on/notification.c src/on/headers.c src/include/notification.h src/include/kernelapi.h src/platform/linux/platform.h
+       (cd src/on; $(CC) $(CCOPTIONS) -c headers.c       -o headers.o      $(COMPILEOPTIONS) $(INCLUDES))
+       (cd src/on; $(CC) $(CCOPTIONS) -c notification.c  -o notification.o $(COMPILEOPTIONS) $(INCLUDES))
+       $(CCLIB),mod-on.so -o mod-on.so src/on/headers.o src/on/notification.o
+       $(STRIP) mod-on.so
        @echo '--------------------'
 
-mod-np.so: src/drivers/np/np.c src/drivers/np/uri2chan.c src/include/kernelapi.h src/platform/linux/platform.h
-       (cd src/drivers/np; $(CC) $(CCOPTIONS) -c np.c      -o np.o   $(COMPILEOPTIONS) $(INCLUDES))
-       (cd src/drivers/np; $(CC) $(CCOPTIONS) -c uri2chan.c -o uri2chan.o $(COMPILEOPTIONS) $(INCLUDES))
-       (cd src/drivers/np; $(CC) $(CCOPTIONS) -c cache.c    -o cache.o $(COMPILEOPTIONS) $(INCLUDES))
-       $(CCLIB),mod-np.so -o mod-np.so src/drivers/np/np.o src/drivers/np/uri2chan.o src/drivers/np/cache.o
-       $(STRIP) mod-np.so
+mod-op.so: src/drivers/op/protocol.c src/drivers/op/uri2chan.c src/include/kernelapi.h src/platform/linux/platform.h
+       (cd src/drivers/op; $(CC) $(CCOPTIONS) -c protocol.c -o protocol.o   $(COMPILEOPTIONS) $(INCLUDES))
+       (cd src/drivers/op; $(CC) $(CCOPTIONS) -c uri2chan.c -o uri2chan.o $(COMPILEOPTIONS) $(INCLUDES))
+       (cd src/drivers/op; $(CC) $(CCOPTIONS) -c cache.c    -o cache.o $(COMPILEOPTIONS) $(INCLUDES))
+       $(CCLIB),mod-op.so -o mod-op.so src/drivers/op/protocol.o src/drivers/op/uri2chan.o src/drivers/op/cache.o
+       $(STRIP) mod-op.so
        @echo '--------------------'
 
-mod-mid.so: src/drivers/nt/mid/mid.c src/include/kernelapi.h src/platform/linux/platform.h
-       (cd src/drivers/nt/mid; $(CC) $(CCOPTIONS) -c mid.c -o mid.o $(COMPILEOPTIONS) $(INCLUDES))
-       $(CCLIB),mod-mid.so -o mod-mid.so src/drivers/nt/mid/mid.o
+mod-mid.so: src/drivers/ot/mid/mid.c src/include/kernelapi.h src/platform/linux/platform.h
+       (cd src/drivers/ot/mid; $(CC) $(CCOPTIONS) -c mid.c -o mid.o $(COMPILEOPTIONS) $(INCLUDES))
+       $(CCLIB),mod-mid.so -o mod-mid.so src/drivers/ot/mid/mid.o
        $(STRIP) mod-mid.so
        @echo '--------------------'
 
-mod-testni.so: src/drivers/nt/test/testni.c src/include/kernelapi.h src/platform/linux/platform.h
-       (cd src/drivers/nt/test; $(CC) $(CCOPTIONS) -c testni.c -o testni.o $(COMPILEOPTIONS) $(INCLUDES))
-       $(CCLIB),mod-testni.so -o mod-testni.so src/drivers/nt/test/testni.o
-       $(STRIP) mod-testni.so
+mod-teston.so: src/drivers/ot/test/teston.c src/include/kernelapi.h src/platform/linux/platform.h
+       (cd src/drivers/ot/test; $(CC) $(CCOPTIONS) -c teston.c -o teston.o $(COMPILEOPTIONS) $(INCLUDES))
+       $(CCLIB),mod-teston.so -o mod-teston.so src/drivers/ot/test/teston.o
+       $(STRIP) mod-teston.so
        @echo '--------------------'
 
 install-lin:
        mv cilux /usr/local/bin
-       mv mod-ni.so mod-np.so /usr/local/lib
+       mv mod-on.so mod-op.so /usr/local/lib
        mkdir -p modules/mid
        mv mod-mid.so modules/mid
-       mkdir -p modules/testni
-       mv mod-testni.so modules/testni
+       mkdir -p modules/teston
+       mv mod-teston.so modules/teston
        @echo '--------------------'
 
 # ---------------------------------------------------------------------------- #
diff --git a/src/drivers/np/cache.c b/src/drivers/np/cache.c
deleted file mode 100644 (file)
index 81133d0..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-extern void   ensure_self_sub(ni_event* evq);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE  4096
-static char   tmpbuf[TMPBUFSIZE];
-
-/* -}{----------------------------------------------------------------------- */
-
-static void cache_read(char*, char*, char*, int, k_stat, void*);
-static void entity_written(char*, char*, char*, int, k_stat, void*);
-static void write_headers(char* path, ni_resource* res);
-static void headers_written(char*, char*, char*, int, k_stat, void*);
-
-
-/* -}{----------------------------------------------------------------------- */
-
-char* make_cache_path(char* uri)
-{
-       char* path;
-       size_t l=strlen(uri);
-       if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
-       if(*(uri+l-1)!='/'){
-               path=k_strdup(uri);
-       }
-       else{
-               path=k_malloc(l+1+10);
-               sprintf(path, "%sindex.html", uri);
-       }
-       return path;
-}
-
-void look_in_file_cache(ni_event* evq)
-{
-       k_hashtable* sub=evq->ent_head;
-       char* uri=k_hashtable_get(sub, "Sub-To:");
-       size_t l=strlen(uri);
-
-       if(l>100){ ensure_self_sub(evq); return; }
-
-       char hdr[128];
-       if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
-       else                sprintf(hdr, "%sindex.html.hdr", uri);
-
-       if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
-       if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
-
-       char* c=strchr(hdr, ':');
-       char* e=strchr(hdr, '/');
-       if(c && c< e) *c='-';
-
-       k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
-}
-
-void save_in_file_cache(ni_resource* res)
-{
-       char*        uri     =res->uri;
-       char*        path    =make_cache_path(uri); if(!path) return;
-       k_hashtable* ent_head=res->ent_head;
-       void*        data    =res->entity;
-       int          partial =k_hashtable_is(     ent_head, "Status:", "206");
-       size_t       size    =k_hashtable_get_int(ent_head, "Content-Length:");
-       char*        conrange=k_hashtable_get(    ent_head, "Content-Range:");
-       int          constant=k_hashtable_is(     ent_head, "CUX:", "C");
-
-       if(!data){
-               write_headers(path, res);
-       }
-       else
-       if(constant){
-               int ok=k_file_sync(data, size);
-               if(!ok){
-                       k_log_err("Failed to write (sync mmap): %s", uri);
-                       k_free(path);
-                       return;
-               }
-               write_headers(path, res);
-       }
-       else{
-               if(partial){
-                       k_log_out("save_in_file_cache partial %s", conrange);
-                       if(!conrange || strncmp(conrange, "0-", 2)){
-                               k_log_err("not saving partial");
-                               k_free(path);
-                               return;
-                       }
-                       size=atoi(conrange+2);
-               }
-               k_log_out("save_in_file_cache updateable: %d bytes", size);
-               k_file_write(".", path, data, size, entity_written, res);
-       }
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void entity_written(char*  basedir,
-                    char*  path,
-                    char*  data,
-                    int    usedmmap,
-                    k_stat kstat,
-                    void*  context)
-{
-       if(data) k_log_out("File cache entity written: %s", path);
-       else{
-               k_log_err("Failed to write entity:    %s", path); 
-               k_free(path);
-               return;
-       }
-       ni_resource* res=context;
-       write_headers(path, res);
-}
-
-void write_headers(char* path, ni_resource* res)
-{
-       snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
-       k_free(path); path=k_strdup(tmpbuf);
-       k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
-       k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
-}
-
-void headers_written(char*  basedir,
-                     char*  path,
-                     char*  data,
-                     int    usedmmap,
-                     k_stat kstat,
-                     void*  context)
-{
-       if(data) k_log_out("File cache headers written: %s", path);
-       else     k_log_err("Failed to write headers:    %s", path);
-       k_free(path);
-}
-
-void cache_read(char*  basedir,
-                char*  path,
-                char*  data,
-                int    usedmmap,
-                k_stat kstat,
-                void*  context)
-{
-       if(!data) k_log_out("no cache of %s", path);
-       else      k_log_out("file cache read: %d  %s", kstat.size, path);
-       char* e=strstr(path, ".hdr");
-       if(e){
-               ni_event* evq=context;
-               if(!data){ k_free(path); ensure_self_sub(evq); return; }
-
-               char* header=data;
-               *(header+kstat.size-2)=0;
-               k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
-               k_hashtable_put(ent_head, "", header);
-               if(!ni_get_headers(header, 0, ent_head)){
-                       k_hashtable_delete(ent_head);
-                       k_free(path);
-                       ensure_self_sub(evq);
-                       return;
-               }
-               ni_event_delete(evq);
-               *e=0;
-               ni_event* evt=ni_event_new(0, 0, ent_head, 0);
-               int constant=k_hashtable_is(ent_head, "CUX:", "C");
-               size_t m=constant? USE_MMAP: USE_MALL;
-               k_file_read(".", path, m, 0, cache_read, evt);
-               return;
-       }
-       ni_event* evt=context;
-       k_free(path);
-       evt->entity=data;
-       ni_event_show(evt, "File Cache Found:");
-       k_event_post("ni", evt);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-
diff --git a/src/drivers/np/np.c b/src/drivers/np/np.c
deleted file mode 100644 (file)
index b33dc10..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE  4096
-static char         tmpbuf[TMPBUFSIZE];
-static k_hashtable* own_resources;
-
-/* -}{----------------------------------------------------------------------- */
-
-extern void  run_tests(void);
-
-extern char*   make_cache_path(char* uri);
-extern void    look_in_file_cache(ni_event* evq);
-extern void    save_in_file_cache(ni_resource* res);
-
-extern void    init_uri2chan(void);
-extern char*   get_host_for(char* uri);
-extern char*   get_channel_for(char* host);
-extern char*   use_ping_info(k_hashtable*, k_channel*);
-extern void    use_from_info(k_hashtable*, k_channel*);
-extern void    ping_tunnels(void);
-extern void    send_ping(k_channel* chan, char* firstline, char* to);
-
-/* -}{----------------------------------------------------------------------- */
-
-static int           handles_resource(char* name);
-static void          sync_resource(ni_resource* res);
-       int           connection_writable(k_channel* chan, int bufpos, int len);
-       int           connection_readable(k_channel* chan, int bufpos, int len);
-static int           recv_next_event(    k_channel* chan);
-static void          recv_request(       k_channel* chan, char* header);
-static void          recv_response(      k_channel* chan, char* header);
-static void          got_mmap(char*, char*, char*, int, k_stat, void*);
-static void          set_read_buffer(k_channel*, char*, size_t, ni_event*);
-static int           recv_entity(        k_channel* chan, int bufpos, int eof);
-static int           expecting_response(char* pub, ni_event* evt, k_channel*);
-static void          do_request(   ni_event* evq);
-       void          ensure_self_sub(ni_event* evq);
-static void          ping_resource_subs(void* arg, char* key, void* val);
-static void          ping_sub(ni_resource* res, k_hashtable* sub);
-static ni_resource* own_resource(char* uri);
-static void          send_request(ni_event* evq);
-static void          send_response(ni_event* evt);
-static k_channel*    ensure_chan(char* chanm);
-
-/* -}{----------------------------------------------------------------------- */
-
-EXPORT int np_module_loaded(void)
-{
-       ni_register_driver("np", handles_resource, sync_resource);
-
-       if(strstr(k_version, "test")){
-               //run_tests();
-       }
-
-       init_uri2chan();
-
-       own_resources=k_hashtable_new("Own Resources", 0);
-
-       k_log_out("NP Driver initialised");
-
-       return 0;
-}
-
-EXPORT void np_module_tick(void)
-{
-       static long tix;
-       tix++;
-       if(!(tix % 1000)){
-               k_hashtable_apply(own_resources, ping_resource_subs, 0);
-       }
-       if(!(tix % 3000)){
-               ping_tunnels();
-       }
-}
-
-EXPORT int np_module_event(void* data)
-{
-       ni_event* evt=data;
-       if(!k_hashtable_get(evt->ent_head, "Status:")){
-               do_request(evt);
-       }
-       else{
-               send_response(evt);
-       }
-       return 0;
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
-       return 0;
-}
-
-void sync_resource(ni_resource* res)
-{
-       save_in_file_cache(res);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-int connection_readable(k_channel* chan, int bufpos, int len)
-{
-       if(0) k_log_out("connection_readable %s %p %d %d %p",
-                                chan->name, chan, bufpos, len, chan->context);
-       int sof=(len==  0);
-       int eof=(len== -1);
-
-       if(sof) return 0;
-
-       do{
-               ni_event* evt=chan->context;
-               if(!evt){
-                       int n=recv_next_event(chan);
-                       if(n<0) break;
-                       bufpos-=n;
-               }
-               else{
-                       int n=recv_entity(chan, bufpos, eof);
-                       if(n<0) break;
-                       bufpos-=n;
-               }
-
-       } while(1);
-
-       if(eof && chan->context){
-               ni_event* evt=chan->context;
-               evt->entity=0;
-               ni_event_delete(evt);
-               chan->context=0;
-       }
-
-       return 0;
-}
-
-int connection_writable(k_channel* chan, int bufpos, int len)
-{
-       if(0) k_log_out("connection_writable %p %d %d %p",
-                                      chan, bufpos, len, chan->context);
-//if(len>20000) exit(1);
-       int sof=(len==  0);
-       int eof=(len== -1);
-
-       if(sof){
-               send_ping(chan, "PING ni/0.5", 0);
-               return 0;
-       }
-
-       if(eof && chan->context){
-               ni_event* evt=chan->context;
-               evt->entity=0;
-               ni_event_delete(evt);
-               chan->context=0;
-       }
-
-       return 0;
-}
-
-/* -}{---- Receiving -------------------------------------------------------- */
-
-int recv_next_event(k_channel* chan)
-{
-       char* header=k_channel_chop_div(chan, CRLF CRLF);
-       if(!header) return -1;
-       int n=strlen(header)+strlen(CRLF CRLF);
-
-       if(!strncmp(header, "GET",  3) ||
-          !strncmp(header, "SUB",  3) ||
-          !strncmp(header, "UNSUB",5) ||
-          !strncmp(header, "HEAD", 4) ||
-          !strncmp(header, "PING", 4)   ){
-
-               recv_request(chan, header);
-               return n;
-       }
-       if(!strncmp(header, "ni/", 4)   ){
-
-               recv_response(chan, header);
-               return n;
-       }
-       k_free(header);
-       k_log_err("Failed reading request or response - closing connection");
-       k_channel_close(chan);
-       return n;
-}
-
-void recv_request(k_channel* chan, char* header)
-{
-       ni_event* evq;
-       evq=ni_get_request_headers(header);
-       if(!evq){
-               k_log_err("Failed reading request headers - closing connection");
-               k_channel_close(chan);
-               return;
-       }
-       if(!k_hashtable_isn(evq->evt_head, "Protocol:", "ni/", 4)){
-               ni_event_delete(evq);
-               k_log_err("Failed reading request not ni - closing connection");
-               k_channel_close(chan);
-               return;
-       }
-
-       k_hashtable* ent_head=evq->ent_head;
-       int ping=k_hashtable_is(ent_head, "Method:", "PING");
-
-       if(!evq->uri && !ping){
-               evq->uri=k_strdup(chan->name);
-               k_hashtable_put_dup(ent_head, "URI:", chan->name);
-       }
-
-       ni_event_show(evq, "ni Protocol Request");
-
-       if(k_hashtable_isi(evq->evt_head, "Connection:", "Keep-Alive")){
-               chan->linger=1;
-               if(k_hashtable_isn(ent_head, "Sub-To:", "./test", 6)){
-                       chan->linger=0;
-               }
-       }
-       if(ping){
-               char* from=use_ping_info(ent_head, chan);
-               if(from) send_ping(chan, "ni/0.5 270 PING", from);
-               ni_event_delete(evq);
-               return;
-       }
-       //use_from_info(ent_head, chan);
-
-       ni_event* evp=ni_event_new(evq->uri, 0, k_hashtable_dup(ent_head), 0);
-
-       ni_event_delete(evq);
-
-       k_event_post("ni", evp);
-}
-
-void recv_response(k_channel* chan, char* header)
-{
-       ni_event* evt=ni_get_response_headers(header);
-       if(!evt){
-               k_log_err("recv_response: headers failed but doing nothing!");
-               return;
-       }
-       char*        pub=     evt->uri;
-       k_hashtable* ent_head=evt->ent_head;
-
-       if(!expecting_response(pub, evt, chan)) return;
-
-       ni_event_show(evt, "Response");
-
-       int head=k_hashtable_is(     ent_head, "Status:", "260");
-       int nmod=k_hashtable_is(     ent_head, "Status:", "304");
-       int ping=k_hashtable_is(     ent_head, "Status:", "270");
-       int cl  =k_hashtable_get_int(ent_head, "Content-Length:");
-       int entity=!(head || nmod || ping || cl==0);
-
-       if(ping){
-               use_ping_info(ent_head, chan);
-               ni_event_delete(evt);
-               return;
-       }
-       use_from_info(ent_head, chan);
-
-       if(entity){
-               k_hashtable_set(ent_head, "Status:",      "260");
-               k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
-       }
-       k_event_post("ni", evt);
-
-       if(entity){
-
-               k_hashtable* eh=k_hashtable_new("nHeaders/recv_response", 1);
-               char* from      =k_hashtable_get(ent_head, "From:");
-               char* contlen   =k_hashtable_get(ent_head, "Content-Length:");
-               char* cux       =k_hashtable_get(ent_head, "CUX:");
-               k_hashtable_set(eh, "Status:",        "206");
-               k_hashtable_set(eh, "Status-Text:",   "Partial Content");
-               k_hashtable_put_dup(eh, "From:",           from);
-               k_hashtable_put_dup(eh, "Content-Length:", contlen);
-               k_hashtable_put_dup(eh, "CUX:",            cux);
-               ni_event* evc=ni_event_new(pub, 0, eh, 0);
-               chan->context=evc;
-
-               int constant=k_hashtable_is(ent_head, "CUX:", "C");
-               if(constant){
-                       char* path=make_cache_path(pub); if(!path) return;
-                       k_file_read(".", path, USE_MMAP, cl, got_mmap, chan);
-               }
-               else{
-                       char* data=k_malloc(cl);
-                       set_read_buffer(chan, data, cl, evc);
-               }
-       }
-}
-
-void got_mmap(char*  basedir,
-              char*  path,
-              char*  data,
-              int    usedmmap,
-              k_stat kstat,
-              void*  context){
-
-       k_free(path);
-       k_channel* chan=context;
-       ni_event* evt=chan->context;
-       if(!evt){ k_log_err("got_mmap: evt=0"); return; }
-       if(!data || !usedmmap){ k_log_err("got_mmap: mmap failed"); return; }
-
-       size_t cl=k_hashtable_get_int(evt->ent_head, "Content-Length:");
-       set_read_buffer(chan, data, cl, evt);
-}
-
-void set_read_buffer(k_channel* chan, char* data, size_t cl, ni_event* evt)
-{
-       evt->entity=data;
-       int r=k_channel_setbuf(chan, data, cl);
-       if(0) k_log_out("k_channel_setbuf %d", r);
-       if(r==BUFFER_ALREADY_SET){
-               k_log_err("oops! k_channel_setbuf BUFFER_ALREADY_SET");
-               return;
-       }
-       if(r==BUFFER_FILLED){
-               k_hashtable_set(evt->ent_head, "Status:",      "200");
-               k_hashtable_set(evt->ent_head, "Status-Text:", "OK");
-               chan->context=0;
-               k_event_post("ni", evt);
-       }
-}
-
-int recv_entity(k_channel* chan, int bufpos, int eof)
-{
-       ni_event*   evt=chan->context;
-       k_hashtable* ent_head=evt->ent_head;
-
-       char* cls=k_hashtable_get(    ent_head, "Content-Length:");
-       int   cl =k_hashtable_get_int(ent_head, "Content-Length:");
-
-       if(!cls && !eof) return -1;
-
-       int partial=0;
-       int eofcontlen=eof && (!cls || bufpos < cl);
-       if(eofcontlen){
-               if(cls){
-                       char* clg=k_strdup(cls);
-                       k_hashtable_put(ent_head, "Content-Length-Given:", clg);
-                       partial=1;
-               }
-               cl=bufpos;
-               char b[32]; snprintf(b, 32, "%d", cl);
-               k_hashtable_put_dup(ent_head, "Content-Length:", b);
-       }
-
-       if(bufpos < cl){
-               if(bufpos){
-                       ni_event* evp=ni_event_dup(evt);
-                       snprintf(tmpbuf, TMPBUFSIZE, "0-%d", bufpos);
-                       char* cr=k_strdup(tmpbuf);
-                       k_hashtable_put(evp->ent_head, "Content-Range:", cr);
-                       k_event_post("ni", evp);
-               }
-               return -1;
-       }
-
-       static char dummy_empty_entity[0];
-       if(!k_channel_getbuf(chan)){
-               int cn=k_hashtable_is(ent_head, "CUX:", "C");
-               if(cl) evt->entity=k_channel_chop_len(chan, cl);
-               else   evt->entity=cn? dummy_empty_entity: k_malloc(1);
-       }
-
-       if(!partial){
-               k_hashtable_set(ent_head, "Status:",      "200");
-               k_hashtable_set(ent_head, "Status-Text:", "OK");
-       }
-       chan->context=0;
-       k_event_post("ni", evt);
-
-       return cl;
-}
-
-int expecting_response(char* pub, ni_event* evt, k_channel* chan)
-{
-       if(pub && 0){
-               k_log_err("unwanted response: %s", pub);
-               ni_event_delete(evt);
-               k_channel_close(chan);
-               return 0;
-       }
-       return 1;
-}
-
-/* -}{---- Sending ---------------------------------------------------------- */
-
-void do_request(ni_event* evq)
-{
-       k_hashtable* sub=evq->ent_head;
-       int tc=k_hashtable_isi(sub, "Sub-Type:", "Cache");
-       int to=k_hashtable_isi(sub, "Sub-Type:", "Original");
-
-       if(tc){
-               char* ims=k_hashtable_get(sub, "If-Modified-Since:");
-               if(ims) ensure_self_sub(evq);
-               else    look_in_file_cache(evq);
-       }
-       else
-       if(to){
-               send_request(evq);
-       }
-}
-
-void ensure_self_sub(ni_event* evq)
-{
-       k_hashtable* sub=evq->ent_head;
-       char*        pub=k_hashtable_get(sub, "Sub-To:");
-
-       ni_resource* res=own_resource(pub);
-       k_hashtable*  enh=res->ent_head;
-       k_hashtable*  selfsub=k_hashtable_get(enh, "Sub-To:");
-       if(selfsub && !k_hashtable_is(selfsub, "Status-Cache:", "OK")){
-               k_log_err("cancel selfsub as new one needed");
-       }
-
-       k_hashtable* ss=k_hashtable_dup(sub);
-       k_hashtable_remove( ss, "From:");
-       k_hashtable_put_dup(ss, "URI:",       pub);
-       k_hashtable_set(    ss, "Sub-Type:", "Original");
-       k_hashtable_put_dup(ss, "Via:",       get_host_for(pub));
-       if(k_hashtable_get( ss, "If-Modified-Since:")){
-               char* lm=k_hashtable_get(enh, "Last-Modified:");
-               if(!res->entity) lm=0;
-               k_hashtable_set(ss, "If-Modified-Since:", lm? lm: "0");
-       }
-       ni_event* evs=ni_event_new(0, 0, ss, 0);
-       k_event_post("ni", evs);
-
-       ni_event_delete(evq);
-}
-
-void ping_resource_subs(void* arg, char* key, void* val)
-{
-       ni_resource* res=val;
-       k_hashtable* pubcache=k_hashtable_get(res->ent_head, "Pub-Cache:");
-       if(!pubcache || !k_hashtable_get(pubcache, "Method:")) return;
-       k_hashtable* subs=k_hashtable_get(res->ent_head, "Sub-To:");
-       k_hashtable* sub;
-       for(sub=subs; sub; sub=sub->next){
-               if(!k_hashtable_is(sub, "Status-Cache:", "OK")){
-                       if(!k_hashtable_get(sub, "Status:")){
-                               ping_sub(res, sub);
-                       }
-                       else{
-                               int ts=k_hashtable_get_int(sub, "Timestamp:");
-                               if(0) k_log_out("check dried-up request: %d", ts);
-                       }
-               }
-       }
-}
-
-void ping_sub(ni_resource* res, k_hashtable* sub)
-{
-       ni_resource_show(res, "ping_resource_subs");
-
-       k_hashtable* ss=k_hashtable_dup(sub);
-
-       char* subto=k_hashtable_extract(ss, "URI:");
-       k_hashtable_put_dup(ss, "URI:",    res->uri);
-       k_hashtable_put(    ss, "Sub-To:", subto);
-       k_hashtable_set(    ss, "Sub-Type:", "Original");
-       k_hashtable_put_dup(ss, "Via:",    get_host_for(res->uri));
-
-       ni_event* evs=ni_event_new(0, 0, ss, 0);
-       k_event_post("ni", evs);
-}
-
-ni_resource* own_resource(char* uri)
-{
-       ni_resource* res=k_hashtable_get(own_resources, uri);
-       if(!res){
-               res=ni_resource_get(uri);
-               k_hashtable_set(own_resources, uri, res);
-       }
-       return res;
-}
-
-void send_request(ni_event* evt)
-{
-       k_hashtable* eh=evt->ent_head;
-       char* method=k_strdup(k_hashtable_get(eh, "Method:"));
-       char* to    =k_strdup(k_hashtable_get(eh, "Sub-To:"));
-       char* via   =k_strdup(k_hashtable_get(eh, "Via:"));
-
-       char* chanm=get_channel_for(via);
-       if(!chanm) goto free_and_return;
-
-       k_channel* chan=ensure_chan(chanm);
-       if(!chan) goto free_and_return;
-
-       ni_fix_ni_headers(eh, 0);
-       ni_request(evt, to, method, chan);
-
-       free_and_return:
-       k_free(method); k_free(to); k_free(via);
-       ni_event_delete(evt);
-}
-
-void send_response(ni_event* evt)
-{
-       ni_event_show(evt, "send_response");
-
-       k_hashtable* eh=evt->ent_head;
-
-       k_hashtable* sub=k_hashtable_get(eh,  "Pub-To:");
-       char* uri       =k_hashtable_get(sub, "URI:");
-       char* from      =k_hashtable_get(sub, "From:");
-       char* method    =k_hashtable_get(sub, "Method:");
-       int   methead   =k_hashtable_is( sub, "Method:", "HEAD");
-
-       char* to=from? from: uri;
-
-       char* host=from? from: get_host_for(uri);
-       char* chanm=get_channel_for(host);
-       if(!chanm){
-               if(0) k_log_out("no ni protocol channel %s", to);
-               ni_event_delete(evt);
-               return;
-       }
-
-       k_channel* chan=ensure_chan(chanm);
-       if(!chan){
-               if(0) k_log_out("no ni protocol channel %s", to);
-               ni_event_delete(evt);
-               return;
-       }
-
-       k_hashtable_extract(eh, "Pub-To:");
-
-       char* protocol="ni/0.5";
-
-       ni_fix_ni_headers(eh, methead);
-       ni_response(evt, to, method, protocol, 0, chan);
-
-       k_hashtable_delete(sub);
-       evt->entity=0;
-       ni_event_delete(evt);
-}
-
-k_channel* ensure_chan(char* chanm)
-{
-       k_channel* chan=k_channel_get_name(chanm);
-       if(!chan){
-               k_log_err("Cannot find current channel for %s", chanm);
-               k_channel_connect_name(chanm, connection_readable,
-                                             connection_writable);
-       }
-       return chan;
-}
-
-/* -}{----------------------------------------------------------------------- */
-
diff --git a/src/drivers/np/uri2chan.c b/src/drivers/np/uri2chan.c
deleted file mode 100644 (file)
index 26b05f2..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-extern int connection_writable(k_channel* chan, int bufpos, int len);
-extern int connection_readable(k_channel* chan, int bufpos, int len);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE  4096
-static char         tmpbuf[TMPBUFSIZE];
-static int          is_np;
-static char*        nexus_channel;
-static k_hashtable* chans_for_host;
-
-/* -}{----------------------------------------------------------------------- */
-
-static void   nexus_file_read(char*, char*, char*, int, k_stat, void*);
-static void   write_nexus(char* hostname);
-static void   nexus_file_written(char*, char*, char*, int, k_stat, void*);
-static int    root_nexus(void);
-static void   listen_http(void);
-static void   listen_nexus(void);
-static void   connect_to_nexus(void);
-static void   ping_this(void* arg, char* key, void* val);
-static char*  generate_new_hostname(k_hashtable* ent_head, k_channel* chan);
-static void   set_channel_for(char* host, char* chanm);
-static void   show_np(void);
-static void   show_list(void* arg, char* key, void* val);
-
-/* -}{----------------------------------------------------------------------- */
-
-void init_uri2chan(void)
-{
-       chans_for_host =k_hashtable_new("Channels for Host", 0);
-
-       k_file_read(".", "nexus.txt", USE_MALL, 0, nexus_file_read, 0);
-
-       is_np=!strcmp(k_ciux, "np");
-       if(is_np)        listen_nexus();
-       if(root_nexus()){
-               k_log_out("root nexus - but listening on http");
-               listen_http();
-       }
-       else{
-               k_log_out("connecting to nexus %s", nexus_channel);
-               connect_to_nexus();
-       }
-}
-
-char* get_host_for(char* uri)
-{
-       if(0) k_log_out("get_host_for %s", uri);
-       char* host=0;
-       if(0) k_log_out("host for %s=%s", uri, host);
-       return host;
-}
-
-char* get_channel_for(char* host)
-{
-       if(0) k_log_out("get_channel_for %s", host);
-       char* chanm=k_hashtable_get(chans_for_host, host);
-       if(!chanm){
-       }
-       if(0) k_log_out("channel for %s=%s", host, chanm);
-       return chanm;
-}
-
-char* use_ping_info(k_hashtable* ent_head, k_channel* chan)
-{
-       char* from=k_hashtable_get(ent_head, "From:");
-       char* to  =k_hashtable_get(ent_head, "To:");
-
-       if(!from) return 0;
-       if(!strcmp(from, "-")) from=generate_new_hostname(ent_head, chan);
-       if(!from) return 0;
-       if(!ni_hostname() && to) write_nexus(to);
-
-       set_channel_for(from, chan->name);
-
-       if(0) k_log_out("%s PING %s", chan->name, from);
-       if(0) show_np();
-
-       return from;
-}
-
-void use_from_info(k_hashtable* ent_head, k_channel* chan)
-{
-       char* from=k_hashtable_get(ent_head, "From:");
-
-       if(!from) return;
-
-       set_channel_for(from, chan->name);
-
-       if(0) show_np();
-}
-
-void ping_tunnels(void)
-{
-       k_hashtable* channelspinged=k_hashtable_new("channelspinged", 0);
-       k_hashtable_apply(chans_for_host, ping_this, channelspinged);
-       k_hashtable_delete(channelspinged);
-}
-
-void send_ping(k_channel* chan, char* firstline, char* to)
-{
-       char* from=ni_hostname();
-       if(!from) from="-";
-
-       int ln=0;
-       int bufsize=TMPBUFSIZE;
-
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s" CRLF, firstline);
-       if(ln>=bufsize) return;
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "From: %s" CRLF, from);
-       if(ln>=bufsize) return;
-       if(to){
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "To: %s" CRLF, to);
-       if(ln>=bufsize) return;
-       }
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "Server: %s" CRLF, k_version);
-       if(ln>=bufsize) return;
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "Channels: %s" CRLF, "-");
-       if(ln>=bufsize) return;
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
-       if(ln>=bufsize) return;
-
-       char* head=k_strdup(tmpbuf);
-       k_channel_send(chan, head, ln, FREE_ON_SENT);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void nexus_file_read(char*  basedir,
-                     char*  filepath,
-                     char*  data,
-                     int    usedmmap,
-                     k_stat kstat,
-                     void*  context)
-{
-       int L=0;
-       if(data) data[kstat.size-1]=0;
-       else     data=k_strdup("");
-       k_hashtable* nex=k_hashtable_new("nexus", 1);
-       if(!ni_get_headers(data, nex, 0)){
-               k_log_err("Corrupt nexus.txt file");
-               k_hashtable_delete(nex);
-               k_free(data);
-               data=k_strdup("");
-               nex=k_hashtable_new("nexus", 1);
-               ni_get_headers(data, nex, 0);
-       }
-
-       char* hostname;
-       nexus_channel=k_hashtable_get_dup(nex, "Nexus-Channel:");
-       hostname     =k_hashtable_get(    nex, "Hostname:");
-
-       if(hostname) ni_hostname_set(hostname);
-
-       if(L) if(nexus_channel) k_log_out("Nexus-Channel: %s", nexus_channel);
-       if(L) if(hostname)      k_log_out("Hostname: %s",      hostname);
-
-       k_hashtable_delete(nex);
-       k_free(data);
-}
-
-void write_nexus(char* hostname)
-{
-       ni_hostname_set(hostname);
-
-       snprintf(tmpbuf, TMPBUFSIZE, "Nexus-Channel: %s\r\n"
-                                    "Hostname:      %s\r\n", nexus_channel,
-                                                             hostname);
-
-       k_file_write(".", "nexus.txt", tmpbuf, strlen(tmpbuf),
-                                      nexus_file_written, 0);
-}
-
-void nexus_file_written(char*  basedir,
-                        char*  filepath,
-                        char*  data,
-                        int    usedmmap,
-                        k_stat kstat,
-                        void*  context)
-{
-       if(!data) k_fatal("Failed to write nexus.txt");
-       else      k_log_out("New nexus.txt written:\n%s", data);
-}
-
-int root_nexus(void)
-{
-       char* hostname=ni_hostname();
-       if(!hostname || strchr(hostname, '-')) return 0;
-       return 1;
-}
-
-void listen_http(void)
-{
-       char* chanm="|nip-server|-|8081|-|";
-       k_channel_connect_name(chanm, connection_readable,
-                                     connection_writable);
-}
-
-void listen_nexus(void)
-{
-       char* chanm="|nip-server|-|7747|-|";
-       k_channel_connect_name(chanm, connection_readable,
-                                     connection_writable);
-}
-
-void connect_to_nexus(void)
-{
-       if(nexus_channel){
-               k_channel_connect_name(nexus_channel, connection_readable,
-                                                     connection_writable);
-       }
-       else k_log_out("discovery of nexus not implemented yet!");
-}
-
-void ping_this(void* arg, char* key, void* val)
-{
-       k_hashtable* channelspinged=arg;
-       char*        chanm=val;
-
-       if(strncmp(chanm, "nip-client", 11)     ) return;
-       if(k_hashtable_get(channelspinged, chanm)) return;
-       k_hashtable_set(channelspinged, chanm, chanm);
-
-       k_channel* chan=k_channel_get_name(chanm);
-       //k_log_out("ping_this: host %s channel %s got=%p", key, chanm, chan);
-
-       if(!chan) k_channel_connect_name(chanm, connection_readable,
-                                               connection_writable);
-
-       int pingtodeath=0;
-       if(chan && pingtodeath) send_ping(chan, "PING ni/0.5", 0);
-}
-
-char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan)
-{
-       if(!ni_hostname()) return 0;
-       unsigned long a=chan->clientip.s_addr;
-       #define IPQUAD(a) \
-               ((unsigned char *)&a)[0], \
-               ((unsigned char *)&a)[1], \
-               ((unsigned char *)&a)[2], \
-               ((unsigned char *)&a)[3]
-       snprintf(tmpbuf, TMPBUFSIZE, "%s-%02x%02x%02x%02x.%d",
-                              ni_hostname(), IPQUAD(a), 7747);
-       if(0) k_log_out("generated new hostname: %s\n", tmpbuf);
-       return k_strdup(tmpbuf);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void set_channel_for(char* host, char* chanm)
-{
-       k_hashtable_put_dup(chans_for_host, host, chanm);
-}
-
-void show_np(void)
-{
-       k_log_out("-------- channel for host ---------------");
-       k_hashtable_apply(chans_for_host,  show_list, 0);
-       k_channel_show_all();
-}
-
-void show_list(void* arg, char* key, void* val)
-{
-       char* chanm=val;
-       k_log_out("%s %s", key, chanm);
-}
-
-void generate_random(void)
-{
-       time_t t=time(0);
-       short r;
-       k_random_bytes((char*)&r, sizeof(r));
-       unsigned char r1=(t >>24) & 255;
-       unsigned char r2=(t >>16) & 255;
-       unsigned char r3=(t >> 8) & 255;
-       unsigned char r4=(t     ) & 255;
-       unsigned char r5=(r >> 8) & 255;
-       unsigned char r6=(r     ) & 255;
-       snprintf(tmpbuf, TMPBUFSIZE, "%02x-%02x-%02x-%02x-%02x-%02x",
-                                     r1, r2, r3, r4, r5, r6);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
diff --git a/src/drivers/nt/mid/mid.c b/src/drivers/nt/mid/mid.c
deleted file mode 100644 (file)
index a684d80..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-
-/* -------------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -------------------------------------------------------------------------- */
-
-#define WINDOW_WIDTH  640
-#define WINDOW_HEIGHT 480
-
-#define POS_ARRAY      0
-#define NORMAL_ARRAY   1
-#define TEXCOORD_ARRAY 2
-
-#define TEX_SIZE 128
-
-/* -------------------------------------------------------------------------- */
-
-static GLfloat xco=   0;
-static GLfloat yco=   1;
-static GLfloat zco= -35;
-static GLfloat view_rotx=0.0, view_roty=0.0, view_rotz=0.0;
-static int     shift=0;
-
-GLuint       program;
-GLuint       texture;
-GLuint       vbo;
-unsigned int numberOfVertices;
-unsigned int posStep;
-unsigned int normStep;
-unsigned int tcStep;
-unsigned int stride;
-float        angle=0.0;
-float        viewAngle = 0.0;
-
-/* -------------------------------------------------------------------------- */
-
-static int  handles_resource(char* name);
-static void sync_resource(ni_resource* res);
-static void init_gl(void);
-static void reshape(int width, int height);
-static void draw(void);
-static void key(unsigned char k, int down);
-
-static int  useTheProgram();
-static int  setUpTnL();
-static int  drawStuff(int width, int height);
-
-/* -------------------------------------------------------------------------- */
-
-EXPORT int mid_module_loaded(void)
-{
-    ni_register_driver("mid", handles_resource, sync_resource);
-
-    init_gl();
-
-    k_gl_register_reshape(reshape);
-    k_gl_register_draw(draw);
-    k_gl_register_key(key);
-
-    k_log_out("MID Driver initialised");
-
-    return 1;
-}
-
-EXPORT int mid_module_event(void* data)
-{
-    k_log_out("MID got event: %p", data);
-    ni_event* evt=data;
-    ni_event_delete(evt);
-    return 1;
-}
-
-EXPORT int mid_module_tick(void)
-{
-    if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
-    return 1;
-}
-
-/* -------------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
-    return 0;
-}
-
-void sync_resource(ni_resource* res)
-{
-}
-
-/* -------------------------------------------------------------------------- */
-
-void init_gl(void)
-{
-    if(!useTheProgram()) k_gl_end();
-    if(!setUpTnL())      k_gl_end();
-}
-
-void reshape(int width, int height)
-{
-}
-
-void draw(void)
-{
-    if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
-}
-
-#define SHIFT 0
-void key(unsigned char k, int down)
-{
-    if(k == 113) viewAngle += 0.1;
-    if(k == 114) viewAngle -= 0.1;
-
-    if(k==SHIFT &&  down){ shift=1; return; }
-    if(k==SHIFT && !down){ shift=0; return; }
-    if(!down) return;
-
-    if(shift) k-=('a'-'A');
-
-    float speed=0.25;
-    switch (k) {
-    case 'H':
-        xco-=speed*(float)sin((view_roty-90)*3.14/180);
-        zco+=speed*(float)cos((view_roty-90)*3.14/180);
-        if(xco< -35) xco= -35;
-        if(xco>  35) xco=  35;
-        if(zco< -35) zco= -35;
-        if(zco>  35) zco=  35;
-    break;
-    case 'L':
-        xco+=speed*(float)sin((view_roty-90)*3.14/180);
-        zco-=speed*(float)cos((view_roty-90)*3.14/180);
-        if(xco< -35) xco= -35;
-        if(xco>  35) xco=  35;
-        if(zco< -35) zco= -35;
-        if(zco>  35) zco=  35;
-    break;
-    case 'i':
-        xco-=speed*(float)sin(view_roty*3.14/180);
-        zco+=speed*(float)cos(view_roty*3.14/180);
-        if(xco< -35) xco= -35;
-        if(xco>  35) xco=  35;
-        if(zco< -35) zco= -35;
-        if(zco>  35) zco=  35;
-    break;
-    case 'o':
-        xco+=speed*(float)sin(view_roty*3.14/180);
-        zco-=speed*(float)cos(view_roty*3.14/180);
-        if(xco< -35) xco= -35;
-        if(xco>  35) xco=  35;
-        if(zco< -35) zco= -35;
-        if(zco>  35) zco=  35;
-    break;
-    case 'j':
-        yco-=speed;
-        if(yco< 0.2) yco= 0.2;
-    break;
-    case 'k':
-        yco+=speed;
-    break;
-    case 'l':
-        view_roty += speed*20;
-    break;
-    case 'h':
-        view_roty -= speed*20;
-    break;
-    case 'J':
-        view_rotx += 2.0;
-    break;
-    case 'K':
-        view_rotx -= 2.0;
-    break;
-    case 'z':
-        view_rotz += 2.0;
-    break;
-    case 'Z':
-        view_rotz -= 2.0;
-    break;
-    default:
-    return;
-    }
-    draw();
-}
-
-/* ------------------------------------------------------------- */
-
-GLuint isShaderError(GLuint thing)
-{
-    GLint isShader = glIsShader(thing);
-
-    GLint ok;
-    if(isShader){
-        glGetShaderiv(thing, GL_COMPILE_STATUS, &ok);
-    }else{
-        glGetProgramiv(thing, GL_LINK_STATUS, &ok);
-    }
-    if(ok) return 0;
-
-    GLint infoLen=0;
-    if(isShader){
-        glGetShaderiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
-    }else{
-        glGetProgramiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
-    }
-    if(infoLen){
-         char* infoLog = malloc(sizeof(char)*infoLen);
-         if(isShader){
-              glGetShaderInfoLog(thing, infoLen, NULL, infoLog);
-         }else{
-              glGetProgramInfoLog(thing, infoLen, NULL, infoLog);
-         }
-         printf("%s: %s\n", isShader? "Shader compile": "Program link", infoLog);
-         free(infoLog);
-    }
-    return 1;
-}
-
-char* file2string(const char *path)
-{
-    FILE *fd;
-    long len, r;
-    char *str;
-    if(!(fd=fopen(path, "r"))) {
-        fprintf(stderr, "Can't open file '%s' for reading\n", path);
-        return NULL;
-    }
-    fseek(fd, 0, SEEK_END);
-    len = ftell(fd);
-    fseek(fd, 0, SEEK_SET);
-    if(!(str=malloc(len*sizeof(char)))) {
-        fprintf(stderr, "Can't malloc space for '%s'\n", path);
-        return NULL;
-    }
-    r = fread(str, sizeof(char), len, fd);
-    str[r-1] = '\0';
-    fclose(fd);
-    return str;
-}
-
-/* ------------------------------------------------------------- */
-
-int useTheProgram()
-{
-    const char *vsSource = file2string("tnl.vert");
-    const char *fsSource = file2string("tnl.frag");
-
-    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
-    glShaderSource(vs, 1, &vsSource, NULL);
-    glCompileShader(vs);
-    if(isShaderError(vs)) return 0;
-    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(fs, 1, &fsSource, NULL);
-    glCompileShader(fs);
-    if(isShaderError(fs)) return 0;
-    free((void*)vsSource);
-    free((void*)fsSource);
-    program = glCreateProgram();
-    glAttachShader(program, vs);
-    glAttachShader(program, fs);
-
-    glBindAttribLocation(program, POS_ARRAY,      "vertPos");
-    glBindAttribLocation(program, NORMAL_ARRAY,   "vertNormal");
-    /* vertNormal and vertTexCoord don't need to be bound here.. ? */
-    glBindAttribLocation(program, TEXCOORD_ARRAY, "vertTexCoord");
-
-    glLinkProgram(program);
-    if(isShaderError(program)) return 0;
-
-    glUseProgram(program);
-
-    glUniform3f(glGetUniformLocation(program, "frameLightDirection"), 1.0, 0.0, 1.0);
-    glUniform1i(glGetUniformLocation(program, "texture"), 0); /* 0 ?? */
-
-    return 1;
-}
-
-int setUpTnL()
-{
-    glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
-
-    glGenTextures(1, &texture);
-    glBindTexture(GL_TEXTURE_2D, texture);
-
-    GLuint* td = malloc(sizeof(GLuint)*TEX_SIZE*TEX_SIZE);
-    int i,j;
-    for(i=0; i<TEX_SIZE; i++)
-    for(j=0; j<TEX_SIZE; j++) {
-        GLuint col = (255L<<24) + ((255L-j*2)<<16) + ((255L-i)<<8) + (255L-i*2);
-        if ( ((i*j)/8) % 2 ) col = (GLuint) (255L<<24) + (255L<<16) + (0L<<8) + (255L);
-        td[j*TEX_SIZE+i] = col;
-    }
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, td);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-    free(td);
-
-    GLfloat trivertices[] = {
-                             -0.4f,-0.4f,0.4f,  // Pos
-                              0.0f,0.0f,1.0f,   // Normal
-                              0.0f,0.0f,        // TexCoord
-
-                              0.4f,-0.0f,0.0f,  // Pos
-                              0.0f,0.0f,1.0f,   // Normal
-                              1.0f,0.0f,        // TexCoord
-
-                              0.0f,0.4f,0.4f,   // Pos
-                              0.5f,0.5f,0.5f,   // Normal
-                              0.5f,1.0f,        // TexCoord
-
-                              0.4f,0.0f,0.4f,   // Pos
-                              0.5f,0.5f,0.5f,   // Normal
-                              0.5f,0.0f,        // TexCoord
-
-                              0.4f,0.4f,0.4f,   // Pos
-                              0.0f,0.0f,1.0f,   // Normal
-                              0.0f,0.0f,        // TexCoord
-
-    };
-
-    numberOfVertices = 4;
-    posStep  = 3 * sizeof(GLfloat);
-    normStep = 3 * sizeof(GLfloat);
-    tcStep   = 2 * sizeof(GLfloat);
-    stride = posStep + normStep + tcStep;
-
-    glGenBuffers(1, &vbo);
-    glBindBuffer(GL_ARRAY_BUFFER, vbo);
-    glBufferData(GL_ARRAY_BUFFER, numberOfVertices * stride, trivertices, GL_STATIC_DRAW);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-    return 1;
-}
-
-int drawStuff(int width, int height)
-{
-    glViewport(0, 0, width, height);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    float TransRotScaleVerticeMatrix[] = {
-        cos(angle),  0, sin(angle), 0,
-        0,           1, 0,          0,
-        -sin(angle), 0, cos(angle), 0,
-        0,           0, 0,          1
-    };
-
-    float ModelViewProjectionMatrix[] = {
-        cos(viewAngle),  0, sin(viewAngle), 0,
-        0,               1, 0,              0,
-        -sin(viewAngle), 0, cos(viewAngle), 0,
-        0,               0, 0,              1
-    };
-
-    float TransRotScaleNormalMatrix[] = {
-        cos(angle),   0,   sin(angle),
-        0,            1,   0,
-        -sin(angle),  0,   cos(angle)
-    };
-
-    glUniformMatrix4fv(glGetUniformLocation(program, "frameTRSV"), 1, GL_FALSE, TransRotScaleVerticeMatrix);
-    glUniformMatrix4fv(glGetUniformLocation(program, "frameMVP"),  1, GL_FALSE, ModelViewProjectionMatrix);
-    glUniformMatrix3fv(glGetUniformLocation(program, "frameTRSN"), 1, GL_FALSE, TransRotScaleNormalMatrix);
-
-
-    glBindBuffer(GL_ARRAY_BUFFER, vbo);
-
-    glEnableVertexAttribArray(POS_ARRAY);
-    glVertexAttribPointer(POS_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, 0);
-
-    glEnableVertexAttribArray(NORMAL_ARRAY);
-    glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, (void*)posStep  );
-
-    glEnableVertexAttribArray(TEXCOORD_ARRAY);
-    glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, stride, (void*)(posStep + normStep) );
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfVertices);
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-    k_gl_swap_buffers();
-
-    angle += .007f;
-
-    return 1;
-}
-
-void deleteStuff(){
-    glDeleteTextures(1, &texture);
-    glDeleteBuffers(1, &vbo);
-    glDeleteProgram(program);
-/*  glDeleteShader();
-    glDeleteShader();*/
-}
-/* ------------------------------------------------------------- */
-
-
-
diff --git a/src/drivers/nt/test/testni.c b/src/drivers/nt/test/testni.c
deleted file mode 100644 (file)
index 87e3709..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-
-/* -------------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -------------------------------------------------------------------------- */
-
-static int  handles_resource(char* name);
-static void sync_resource(ni_resource* res);
-
-static void start_tests(void);
-static void running_tests(ni_event* evt);
-
-static void test_state(n_object* o, char* os, char* uid, char* cont);
-
-/* -------------------------------------------------------------------------- */
-
-EXPORT int testni_module_loaded(void)
-{
-    ni_register_driver("testni", handles_resource, sync_resource);
-
-    k_log_out("Test NI Driver initialised");
-
-    start_tests();
-
-    return 1;
-}
-
-EXPORT int testni_module_event(void* data)
-{
-    ni_event* evt=data;
-
-    running_tests(evt);
-
-    ni_event_delete(evt);
-    return 1;
-}
-
-EXPORT int testni_module_tick(void)
-{
-    return 1;
-}
-
-/* -------------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
-    return 1;
-}
-
-void sync_resource(ni_resource* res)
-{
-}
-
-/* -------------------------------------------------------------------------- */
-
-/*
- - object.create .update .commit .rollback (auto inc version #?)
- - object.see - may return empty so wait for ..
- - seestate(object) - state asked for /or/ object is subscribing
- */
-void start_tests(void)
-{
-    k_log_out("Creating o11111");
-
-    char* o11111s = "UID: 11111-4141a\n"
-                    "\n"
-                    "This: is one content\n";
-
-    n_object* o11111 = n_object_new(o11111s);
-
-    test_state(o11111, o11111s, "11111-4141a", "is one content");
-
-    k_log_out("Committing o11111");
-
-    n_commit(o11111);
-
-    k_log_out("Creating o22222");
-
-    char* o22222s = "UID: 22222-ef990\n"
-                    "\n"
-                    "This: is two content\n";
-
-    n_object* o22222 = n_object_new(o22222s);
-
-    test_state(o22222, o22222s, "22222-ef990", "is two content");
-
-    n_object* o2 = n_see(o11111, "22222-ef990");
-
-    k_assert(!o2, "Object 2 has not been committed yet, but Object 1 can see it:\n%s\n", n_to_string(o2));
-
-    n_commit(o22222);
-
-    o2 = n_see(o11111, "22222-ef990");
-
-    k_assert(o2!=0, "Object 2 has been committed, but can't be seen by Object 1");
-
-    test_state(o2, o22222s, "22222-ef990", "is two content");
-
-    n_object* o3 = n_see(o22222, "33333-18bbc");
-
-    k_assert(!o3, "Object 3 has not been created yet, but Object 2 can see it:\n%s", n_to_string(o3));
-}
-
-void running_tests(ni_event* evt)
-{
-    char* o33333s = 
-            "UID: 33333-18bbc\n"
-            "\n"
-            "This: is three content\n";
-
-    n_object* o33333 = n_object_new(o33333s);
-
-    n_commit(o33333);
-
-}
-
-/* -------------------------------------------------------------------------- */
-
-void test_state(n_object* o, char* os, char* uid, char* cont)
-{
-    char* c;
-
-    k_log_out("Checking %s", uid);
-
-    c=n_to_string(o);
-    k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
-
-    c=n_uid(o);
-    k_assert(c && !strcmp(c, uid), "UID was %s in n_uid",  c? c: "null");
-
-    c=n_header(o, "UID");
-    k_assert(c && !strcmp(c, uid), "UID was %s in n_header",  c? c: "null");
-
-    c=k_hashtable_get(n_headers(o), "UID");
-    k_assert(c && !strcmp(c, uid), "UID was %s in hash get",  c? c: "null");
-
-    c=k_hashtable_get(n_content(o), "This");
-    k_assert(c && !strcmp(c, cont), "Content was %s", c? c: "null");
-
-    c=n_to_string(o);
-    k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-
diff --git a/src/drivers/op/cache.c b/src/drivers/op/cache.c
new file mode 100644 (file)
index 0000000..fcc7f5b
--- /dev/null
@@ -0,0 +1,182 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+extern void   ensure_self_sub(ni_event* evq);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE  4096
+static char   tmpbuf[TMPBUFSIZE];
+
+/* -}{----------------------------------------------------------------------- */
+
+static void cache_read(char*, char*, char*, int, k_stat, void*);
+static void entity_written(char*, char*, char*, int, k_stat, void*);
+static void write_headers(char* path, ni_resource* res);
+static void headers_written(char*, char*, char*, int, k_stat, void*);
+
+
+/* -}{----------------------------------------------------------------------- */
+
+char* make_cache_path(char* uri)
+{
+       char* path;
+       size_t l=strlen(uri);
+       if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
+       if(*(uri+l-1)!='/'){
+               path=k_strdup(uri);
+       }
+       else{
+               path=k_malloc(l+1+10);
+               sprintf(path, "%sindex.html", uri);
+       }
+       return path;
+}
+
+void look_in_file_cache(ni_event* evq)
+{
+       k_hashtable* sub=evq->ent_head;
+       char* uri=k_hashtable_get(sub, "Sub-To:");
+       size_t l=strlen(uri);
+
+       if(l>100){ ensure_self_sub(evq); return; }
+
+       char hdr[128];
+       if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
+       else                sprintf(hdr, "%sindex.html.hdr", uri);
+
+       if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
+       if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
+
+       char* c=strchr(hdr, ':');
+       char* e=strchr(hdr, '/');
+       if(c && c< e) *c='-';
+
+       k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
+}
+
+void save_in_file_cache(ni_resource* res)
+{
+       char*        uri     =res->uri;
+       char*        path    =make_cache_path(uri); if(!path) return;
+       k_hashtable* ent_head=res->ent_head;
+       void*        data    =res->entity;
+       int          partial =k_hashtable_is(     ent_head, "Status:", "206");
+       size_t       size    =k_hashtable_get_int(ent_head, "Content-Length:");
+       char*        conrange=k_hashtable_get(    ent_head, "Content-Range:");
+       int          constant=k_hashtable_is(     ent_head, "CUX:", "C");
+
+       if(!data){
+               write_headers(path, res);
+       }
+       else
+       if(constant){
+               int ok=k_file_sync(data, size);
+               if(!ok){
+                       k_log_err("Failed to write (sync mmap): %s", uri);
+                       k_free(path);
+                       return;
+               }
+               write_headers(path, res);
+       }
+       else{
+               if(partial){
+                       k_log_out("save_in_file_cache partial %s", conrange);
+                       if(!conrange || strncmp(conrange, "0-", 2)){
+                               k_log_err("not saving partial");
+                               k_free(path);
+                               return;
+                       }
+                       size=atoi(conrange+2);
+               }
+               k_log_out("save_in_file_cache updateable: %d bytes", size);
+               k_file_write(".", path, data, size, entity_written, res);
+       }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void entity_written(char*  basedir,
+                    char*  path,
+                    char*  data,
+                    int    usedmmap,
+                    k_stat kstat,
+                    void*  context)
+{
+       if(data) k_log_out("File cache entity written: %s", path);
+       else{
+               k_log_err("Failed to write entity:    %s", path); 
+               k_free(path);
+               return;
+       }
+       ni_resource* res=context;
+       write_headers(path, res);
+}
+
+void write_headers(char* path, ni_resource* res)
+{
+       snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
+       k_free(path); path=k_strdup(tmpbuf);
+       k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
+       k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
+}
+
+void headers_written(char*  basedir,
+                     char*  path,
+                     char*  data,
+                     int    usedmmap,
+                     k_stat kstat,
+                     void*  context)
+{
+       if(data) k_log_out("File cache headers written: %s", path);
+       else     k_log_err("Failed to write headers:    %s", path);
+       k_free(path);
+}
+
+void cache_read(char*  basedir,
+                char*  path,
+                char*  data,
+                int    usedmmap,
+                k_stat kstat,
+                void*  context)
+{
+       if(!data) k_log_out("no cache of %s", path);
+       else      k_log_out("file cache read: %d  %s", kstat.size, path);
+       char* e=strstr(path, ".hdr");
+       if(e){
+               ni_event* evq=context;
+               if(!data){ k_free(path); ensure_self_sub(evq); return; }
+
+               char* header=data;
+               *(header+kstat.size-2)=0;
+               k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
+               k_hashtable_put(ent_head, "", header);
+               if(!ni_get_headers(header, 0, ent_head)){
+                       k_hashtable_delete(ent_head);
+                       k_free(path);
+                       ensure_self_sub(evq);
+                       return;
+               }
+               ni_event_delete(evq);
+               *e=0;
+               ni_event* evt=ni_event_new(0, 0, ent_head, 0);
+               int constant=k_hashtable_is(ent_head, "CUX:", "C");
+               size_t m=constant? USE_MMAP: USE_MALL;
+               k_file_read(".", path, m, 0, cache_read, evt);
+               return;
+       }
+       ni_event* evt=context;
+       k_free(path);
+       evt->entity=data;
+       ni_event_show(evt, "File Cache Found:");
+       k_event_post("on", evt);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+
diff --git a/src/drivers/op/protocol.c b/src/drivers/op/protocol.c
new file mode 100644 (file)
index 0000000..ce964a9
--- /dev/null
@@ -0,0 +1,562 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE  4096
+static char         tmpbuf[TMPBUFSIZE];
+static k_hashtable* own_resources;
+
+/* -}{----------------------------------------------------------------------- */
+
+extern void  run_tests(void);
+
+extern char*   make_cache_path(char* uri);
+extern void    look_in_file_cache(ni_event* evq);
+extern void    save_in_file_cache(ni_resource* res);
+
+extern void    init_uri2chan(void);
+extern char*   get_host_for(char* uri);
+extern char*   get_channel_for(char* host);
+extern char*   use_ping_info(k_hashtable*, k_channel*);
+extern void    use_from_info(k_hashtable*, k_channel*);
+extern void    ping_tunnels(void);
+extern void    send_ping(k_channel* chan, char* firstline, char* to);
+
+/* -}{----------------------------------------------------------------------- */
+
+static int           handles_resource(char* name);
+static void          sync_resource(ni_resource* res);
+       int           connection_writable(k_channel* chan, int bufpos, int len);
+       int           connection_readable(k_channel* chan, int bufpos, int len);
+static int           recv_next_event(    k_channel* chan);
+static void          recv_request(       k_channel* chan, char* header);
+static void          recv_response(      k_channel* chan, char* header);
+static void          got_mmap(char*, char*, char*, int, k_stat, void*);
+static void          set_read_buffer(k_channel*, char*, size_t, ni_event*);
+static int           recv_entity(        k_channel* chan, int bufpos, int eof);
+static int           expecting_response(char* pub, ni_event* evt, k_channel*);
+static void          do_request(   ni_event* evq);
+       void          ensure_self_sub(ni_event* evq);
+static void          ping_resource_subs(void* arg, char* key, void* val);
+static void          ping_sub(ni_resource* res, k_hashtable* sub);
+static ni_resource* own_resource(char* uri);
+static void          send_request(ni_event* evq);
+static void          send_response(ni_event* evt);
+static k_channel*    ensure_chan(char* chanm);
+
+/* -}{----------------------------------------------------------------------- */
+
+EXPORT int op_module_loaded(void)
+{
+       ni_register_driver("op", handles_resource, sync_resource);
+
+       if(strstr(k_version, "test")){
+               //run_tests();
+       }
+
+       init_uri2chan();
+
+       own_resources=k_hashtable_new("Own Resources", 0);
+
+       k_log_out("OP Driver initialised");
+
+       return 0;
+}
+
+EXPORT void op_module_tick(void)
+{
+       static long tix;
+       tix++;
+       if(!(tix % 1000)){
+               k_hashtable_apply(own_resources, ping_resource_subs, 0);
+       }
+       if(!(tix % 3000)){
+               ping_tunnels();
+       }
+}
+
+EXPORT int op_module_event(void* data)
+{
+       ni_event* evt=data;
+       if(!k_hashtable_get(evt->ent_head, "Status:")){
+               do_request(evt);
+       }
+       else{
+               send_response(evt);
+       }
+       return 0;
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+       return 0;
+}
+
+void sync_resource(ni_resource* res)
+{
+       save_in_file_cache(res);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+int connection_readable(k_channel* chan, int bufpos, int len)
+{
+       if(0) k_log_out("connection_readable %s %p %d %d %p",
+                                chan->name, chan, bufpos, len, chan->context);
+       int sof=(len==  0);
+       int eof=(len== -1);
+
+       if(sof) return 0;
+
+       do{
+               ni_event* evt=chan->context;
+               if(!evt){
+                       int n=recv_next_event(chan);
+                       if(n<0) break;
+                       bufpos-=n;
+               }
+               else{
+                       int n=recv_entity(chan, bufpos, eof);
+                       if(n<0) break;
+                       bufpos-=n;
+               }
+
+       } while(1);
+
+       if(eof && chan->context){
+               ni_event* evt=chan->context;
+               evt->entity=0;
+               ni_event_delete(evt);
+               chan->context=0;
+       }
+
+       return 0;
+}
+
+int connection_writable(k_channel* chan, int bufpos, int len)
+{
+       if(0) k_log_out("connection_writable %p %d %d %p",
+                                      chan, bufpos, len, chan->context);
+//if(len>20000) exit(1);
+       int sof=(len==  0);
+       int eof=(len== -1);
+
+       if(sof){
+               send_ping(chan, "PING OP/0.5", 0);
+               return 0;
+       }
+
+       if(eof && chan->context){
+               ni_event* evt=chan->context;
+               evt->entity=0;
+               ni_event_delete(evt);
+               chan->context=0;
+       }
+
+       return 0;
+}
+
+/* -}{---- Receiving -------------------------------------------------------- */
+
+int recv_next_event(k_channel* chan)
+{
+       char* header=k_channel_chop_div(chan, CRLF CRLF);
+       if(!header) return -1;
+       int n=strlen(header)+strlen(CRLF CRLF);
+
+       if(!strncmp(header, "GET",  3) ||
+          !strncmp(header, "SUB",  3) ||
+          !strncmp(header, "UNSUB",5) ||
+          !strncmp(header, "HEAD", 4) ||
+          !strncmp(header, "PING", 4)   ){
+
+               recv_request(chan, header);
+               return n;
+       }
+       if(!strncmp(header, "OP/", 4)   ){
+
+               recv_response(chan, header);
+               return n;
+       }
+       k_free(header);
+       k_log_err("Failed reading request or response - closing connection");
+       k_channel_close(chan);
+       return n;
+}
+
+void recv_request(k_channel* chan, char* header)
+{
+       ni_event* evq;
+       evq=ni_get_request_headers(header);
+       if(!evq){
+               k_log_err("Failed reading request headers - closing connection");
+               k_channel_close(chan);
+               return;
+       }
+       if(!k_hashtable_isn(evq->evt_head, "Protocol:", "OP/", 4)){
+               ni_event_delete(evq);
+               k_log_err("Failed reading request not OP - closing connection");
+               k_channel_close(chan);
+               return;
+       }
+
+       k_hashtable* ent_head=evq->ent_head;
+       int ping=k_hashtable_is(ent_head, "Method:", "PING");
+
+       if(!evq->uri && !ping){
+               evq->uri=k_strdup(chan->name);
+               k_hashtable_put_dup(ent_head, "URI:", chan->name);
+       }
+
+       ni_event_show(evq, "OP Protocol Request");
+
+       if(k_hashtable_isi(evq->evt_head, "Connection:", "Keep-Alive")){
+               chan->linger=1;
+               if(k_hashtable_isn(ent_head, "Sub-To:", "./test", 6)){
+                       chan->linger=0;
+               }
+       }
+       if(ping){
+               char* from=use_ping_info(ent_head, chan);
+               if(from) send_ping(chan, "OP/0.5 270 PING", from);
+               ni_event_delete(evq);
+               return;
+       }
+       //use_from_info(ent_head, chan);
+
+       ni_event* evp=ni_event_new(evq->uri, 0, k_hashtable_dup(ent_head), 0);
+
+       ni_event_delete(evq);
+
+       k_event_post("on", evp);
+}
+
+void recv_response(k_channel* chan, char* header)
+{
+       ni_event* evt=ni_get_response_headers(header);
+       if(!evt){
+               k_log_err("recv_response: headers failed but doing nothing!");
+               return;
+       }
+       char*        pub=     evt->uri;
+       k_hashtable* ent_head=evt->ent_head;
+
+       if(!expecting_response(pub, evt, chan)) return;
+
+       ni_event_show(evt, "Response");
+
+       int head=k_hashtable_is(     ent_head, "Status:", "260");
+       int nmod=k_hashtable_is(     ent_head, "Status:", "304");
+       int ping=k_hashtable_is(     ent_head, "Status:", "270");
+       int cl  =k_hashtable_get_int(ent_head, "Content-Length:");
+       int entity=!(head || nmod || ping || cl==0);
+
+       if(ping){
+               use_ping_info(ent_head, chan);
+               ni_event_delete(evt);
+               return;
+       }
+       use_from_info(ent_head, chan);
+
+       if(entity){
+               k_hashtable_set(ent_head, "Status:",      "260");
+               k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
+       }
+       k_event_post("on", evt);
+
+       if(entity){
+
+               k_hashtable* eh=k_hashtable_new("nHeaders/recv_response", 1);
+               char* from      =k_hashtable_get(ent_head, "From:");
+               char* contlen   =k_hashtable_get(ent_head, "Content-Length:");
+               char* cux       =k_hashtable_get(ent_head, "CUX:");
+               k_hashtable_set(eh, "Status:",        "206");
+               k_hashtable_set(eh, "Status-Text:",   "Partial Content");
+               k_hashtable_put_dup(eh, "From:",           from);
+               k_hashtable_put_dup(eh, "Content-Length:", contlen);
+               k_hashtable_put_dup(eh, "CUX:",            cux);
+               ni_event* evc=ni_event_new(pub, 0, eh, 0);
+               chan->context=evc;
+
+               int constant=k_hashtable_is(ent_head, "CUX:", "C");
+               if(constant){
+                       char* path=make_cache_path(pub); if(!path) return;
+                       k_file_read(".", path, USE_MMAP, cl, got_mmap, chan);
+               }
+               else{
+                       char* data=k_malloc(cl);
+                       set_read_buffer(chan, data, cl, evc);
+               }
+       }
+}
+
+void got_mmap(char*  basedir,
+              char*  path,
+              char*  data,
+              int    usedmmap,
+              k_stat kstat,
+              void*  context){
+
+       k_free(path);
+       k_channel* chan=context;
+       ni_event* evt=chan->context;
+       if(!evt){ k_log_err("got_mmap: evt=0"); return; }
+       if(!data || !usedmmap){ k_log_err("got_mmap: mmap failed"); return; }
+
+       size_t cl=k_hashtable_get_int(evt->ent_head, "Content-Length:");
+       set_read_buffer(chan, data, cl, evt);
+}
+
+void set_read_buffer(k_channel* chan, char* data, size_t cl, ni_event* evt)
+{
+       evt->entity=data;
+       int r=k_channel_setbuf(chan, data, cl);
+       if(0) k_log_out("k_channel_setbuf %d", r);
+       if(r==BUFFER_ALREADY_SET){
+               k_log_err("oops! k_channel_setbuf BUFFER_ALREADY_SET");
+               return;
+       }
+       if(r==BUFFER_FILLED){
+               k_hashtable_set(evt->ent_head, "Status:",      "200");
+               k_hashtable_set(evt->ent_head, "Status-Text:", "OK");
+               chan->context=0;
+               k_event_post("on", evt);
+       }
+}
+
+int recv_entity(k_channel* chan, int bufpos, int eof)
+{
+       ni_event*   evt=chan->context;
+       k_hashtable* ent_head=evt->ent_head;
+
+       char* cls=k_hashtable_get(    ent_head, "Content-Length:");
+       int   cl =k_hashtable_get_int(ent_head, "Content-Length:");
+
+       if(!cls && !eof) return -1;
+
+       int partial=0;
+       int eofcontlen=eof && (!cls || bufpos < cl);
+       if(eofcontlen){
+               if(cls){
+                       char* clg=k_strdup(cls);
+                       k_hashtable_put(ent_head, "Content-Length-Given:", clg);
+                       partial=1;
+               }
+               cl=bufpos;
+               char b[32]; snprintf(b, 32, "%d", cl);
+               k_hashtable_put_dup(ent_head, "Content-Length:", b);
+       }
+
+       if(bufpos < cl){
+               if(bufpos){
+                       ni_event* evp=ni_event_dup(evt);
+                       snprintf(tmpbuf, TMPBUFSIZE, "0-%d", bufpos);
+                       char* cr=k_strdup(tmpbuf);
+                       k_hashtable_put(evp->ent_head, "Content-Range:", cr);
+                       k_event_post("on", evp);
+               }
+               return -1;
+       }
+
+       static char dummy_empty_entity[0];
+       if(!k_channel_getbuf(chan)){
+               int cn=k_hashtable_is(ent_head, "CUX:", "C");
+               if(cl) evt->entity=k_channel_chop_len(chan, cl);
+               else   evt->entity=cn? dummy_empty_entity: k_malloc(1);
+       }
+
+       if(!partial){
+               k_hashtable_set(ent_head, "Status:",      "200");
+               k_hashtable_set(ent_head, "Status-Text:", "OK");
+       }
+       chan->context=0;
+       k_event_post("on", evt);
+
+       return cl;
+}
+
+int expecting_response(char* pub, ni_event* evt, k_channel* chan)
+{
+       if(pub && 0){
+               k_log_err("unwanted response: %s", pub);
+               ni_event_delete(evt);
+               k_channel_close(chan);
+               return 0;
+       }
+       return 1;
+}
+
+/* -}{---- Sending ---------------------------------------------------------- */
+
+void do_request(ni_event* evq)
+{
+       k_hashtable* sub=evq->ent_head;
+       int tc=k_hashtable_isi(sub, "Sub-Type:", "Cache");
+       int to=k_hashtable_isi(sub, "Sub-Type:", "Original");
+
+       if(tc){
+               char* ims=k_hashtable_get(sub, "If-Modified-Since:");
+               if(ims) ensure_self_sub(evq);
+               else    look_in_file_cache(evq);
+       }
+       else
+       if(to){
+               send_request(evq);
+       }
+}
+
+void ensure_self_sub(ni_event* evq)
+{
+       k_hashtable* sub=evq->ent_head;
+       char*        pub=k_hashtable_get(sub, "Sub-To:");
+
+       ni_resource* res=own_resource(pub);
+       k_hashtable*  enh=res->ent_head;
+       k_hashtable*  selfsub=k_hashtable_get(enh, "Sub-To:");
+       if(selfsub && !k_hashtable_is(selfsub, "Status-Cache:", "OK")){
+               k_log_err("cancel selfsub as new one needed");
+       }
+
+       k_hashtable* ss=k_hashtable_dup(sub);
+       k_hashtable_remove( ss, "From:");
+       k_hashtable_put_dup(ss, "URI:",       pub);
+       k_hashtable_set(    ss, "Sub-Type:", "Original");
+       k_hashtable_put_dup(ss, "Via:",       get_host_for(pub));
+       if(k_hashtable_get( ss, "If-Modified-Since:")){
+               char* lm=k_hashtable_get(enh, "Last-Modified:");
+               if(!res->entity) lm=0;
+               k_hashtable_set(ss, "If-Modified-Since:", lm? lm: "0");
+       }
+       ni_event* evs=ni_event_new(0, 0, ss, 0);
+       k_event_post("on", evs);
+
+       ni_event_delete(evq);
+}
+
+void ping_resource_subs(void* arg, char* key, void* val)
+{
+       ni_resource* res=val;
+       k_hashtable* pubcache=k_hashtable_get(res->ent_head, "Pub-Cache:");
+       if(!pubcache || !k_hashtable_get(pubcache, "Method:")) return;
+       k_hashtable* subs=k_hashtable_get(res->ent_head, "Sub-To:");
+       k_hashtable* sub;
+       for(sub=subs; sub; sub=sub->next){
+               if(!k_hashtable_is(sub, "Status-Cache:", "OK")){
+                       if(!k_hashtable_get(sub, "Status:")){
+                               ping_sub(res, sub);
+                       }
+                       else{
+                               int ts=k_hashtable_get_int(sub, "Timestamp:");
+                               if(0) k_log_out("check dried-up request: %d", ts);
+                       }
+               }
+       }
+}
+
+void ping_sub(ni_resource* res, k_hashtable* sub)
+{
+       ni_resource_show(res, "ping_resource_subs");
+
+       k_hashtable* ss=k_hashtable_dup(sub);
+
+       char* subto=k_hashtable_extract(ss, "URI:");
+       k_hashtable_put_dup(ss, "URI:",    res->uri);
+       k_hashtable_put(    ss, "Sub-To:", subto);
+       k_hashtable_set(    ss, "Sub-Type:", "Original");
+       k_hashtable_put_dup(ss, "Via:",    get_host_for(res->uri));
+
+       ni_event* evs=ni_event_new(0, 0, ss, 0);
+       k_event_post("on", evs);
+}
+
+ni_resource* own_resource(char* uri)
+{
+       ni_resource* res=k_hashtable_get(own_resources, uri);
+       if(!res){
+               res=ni_resource_get(uri);
+               k_hashtable_set(own_resources, uri, res);
+       }
+       return res;
+}
+
+void send_request(ni_event* evt)
+{
+       k_hashtable* eh=evt->ent_head;
+       char* method=k_strdup(k_hashtable_get(eh, "Method:"));
+       char* to    =k_strdup(k_hashtable_get(eh, "Sub-To:"));
+       char* via   =k_strdup(k_hashtable_get(eh, "Via:"));
+
+       char* chanm=get_channel_for(via);
+       if(!chanm) goto free_and_return;
+
+       k_channel* chan=ensure_chan(chanm);
+       if(!chan) goto free_and_return;
+
+       ni_fix_ni_headers(eh, 0);
+       ni_request(evt, to, method, chan);
+
+       free_and_return:
+       k_free(method); k_free(to); k_free(via);
+       ni_event_delete(evt);
+}
+
+void send_response(ni_event* evt)
+{
+       ni_event_show(evt, "send_response");
+
+       k_hashtable* eh=evt->ent_head;
+
+       k_hashtable* sub=k_hashtable_get(eh,  "Pub-To:");
+       char* uri       =k_hashtable_get(sub, "URI:");
+       char* from      =k_hashtable_get(sub, "From:");
+       char* method    =k_hashtable_get(sub, "Method:");
+       int   methead   =k_hashtable_is( sub, "Method:", "HEAD");
+
+       char* to=from? from: uri;
+
+       char* host=from? from: get_host_for(uri);
+       char* chanm=get_channel_for(host);
+       if(!chanm){
+               if(0) k_log_out("no OP protocol channel %s", to);
+               ni_event_delete(evt);
+               return;
+       }
+
+       k_channel* chan=ensure_chan(chanm);
+       if(!chan){
+               if(0) k_log_out("no OP protocol channel %s", to);
+               ni_event_delete(evt);
+               return;
+       }
+
+       k_hashtable_extract(eh, "Pub-To:");
+
+       char* protocol="OP/0.5";
+
+       ni_fix_ni_headers(eh, methead);
+       ni_response(evt, to, method, protocol, 0, chan);
+
+       k_hashtable_delete(sub);
+       evt->entity=0;
+       ni_event_delete(evt);
+}
+
+k_channel* ensure_chan(char* chanm)
+{
+       k_channel* chan=k_channel_get_name(chanm);
+       if(!chan){
+               k_log_err("Cannot find current channel for %s", chanm);
+               k_channel_connect_name(chanm, connection_readable,
+                                             connection_writable);
+       }
+       return chan;
+}
+
+/* -}{----------------------------------------------------------------------- */
+
diff --git a/src/drivers/op/uri2chan.c b/src/drivers/op/uri2chan.c
new file mode 100644 (file)
index 0000000..8586433
--- /dev/null
@@ -0,0 +1,294 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+extern int connection_writable(k_channel* chan, int bufpos, int len);
+extern int connection_readable(k_channel* chan, int bufpos, int len);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE  4096
+static char         tmpbuf[TMPBUFSIZE];
+static int          is_np;
+static char*        nexus_channel;
+static k_hashtable* chans_for_host;
+
+/* -}{----------------------------------------------------------------------- */
+
+static void   nexus_file_read(char*, char*, char*, int, k_stat, void*);
+static void   write_nexus(char* hostname);
+static void   nexus_file_written(char*, char*, char*, int, k_stat, void*);
+static int    root_nexus(void);
+static void   listen_http(void);
+static void   listen_nexus(void);
+static void   connect_to_nexus(void);
+static void   ping_this(void* arg, char* key, void* val);
+static char*  generate_new_hostname(k_hashtable* ent_head, k_channel* chan);
+static void   set_channel_for(char* host, char* chanm);
+static void   show_np(void);
+static void   show_list(void* arg, char* key, void* val);
+
+/* -}{----------------------------------------------------------------------- */
+
+void init_uri2chan(void)
+{
+       chans_for_host =k_hashtable_new("Channels for Host", 0);
+
+       k_file_read(".", "nexus.txt", USE_MALL, 0, nexus_file_read, 0);
+
+       is_np=!strcmp(k_ciux, "op");
+       if(is_np)        listen_nexus();
+       if(root_nexus()){
+               k_log_out("root nexus - but listening on http");
+               listen_http();
+       }
+       else{
+               k_log_out("connecting to nexus %s", nexus_channel);
+               connect_to_nexus();
+       }
+}
+
+char* get_host_for(char* uri)
+{
+       if(0) k_log_out("get_host_for %s", uri);
+       char* host=0;
+       if(0) k_log_out("host for %s=%s", uri, host);
+       return host;
+}
+
+char* get_channel_for(char* host)
+{
+       if(0) k_log_out("get_channel_for %s", host);
+       char* chanm=k_hashtable_get(chans_for_host, host);
+       if(!chanm){
+       }
+       if(0) k_log_out("channel for %s=%s", host, chanm);
+       return chanm;
+}
+
+char* use_ping_info(k_hashtable* ent_head, k_channel* chan)
+{
+       char* from=k_hashtable_get(ent_head, "From:");
+       char* to  =k_hashtable_get(ent_head, "To:");
+
+       if(!from) return 0;
+       if(!strcmp(from, "-")) from=generate_new_hostname(ent_head, chan);
+       if(!from) return 0;
+       if(!ni_hostname() && to) write_nexus(to);
+
+       set_channel_for(from, chan->name);
+
+       if(0) k_log_out("%s PING %s", chan->name, from);
+       if(0) show_np();
+
+       return from;
+}
+
+void use_from_info(k_hashtable* ent_head, k_channel* chan)
+{
+       char* from=k_hashtable_get(ent_head, "From:");
+
+       if(!from) return;
+
+       set_channel_for(from, chan->name);
+
+       if(0) show_np();
+}
+
+void ping_tunnels(void)
+{
+       k_hashtable* channelspinged=k_hashtable_new("channelspinged", 0);
+       k_hashtable_apply(chans_for_host, ping_this, channelspinged);
+       k_hashtable_delete(channelspinged);
+}
+
+void send_ping(k_channel* chan, char* firstline, char* to)
+{
+       char* from=ni_hostname();
+       if(!from) from="-";
+
+       int ln=0;
+       int bufsize=TMPBUFSIZE;
+
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s" CRLF, firstline);
+       if(ln>=bufsize) return;
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "From: %s" CRLF, from);
+       if(ln>=bufsize) return;
+       if(to){
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "To: %s" CRLF, to);
+       if(ln>=bufsize) return;
+       }
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "Server: %s" CRLF, k_version);
+       if(ln>=bufsize) return;
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "Channels: %s" CRLF, "-");
+       if(ln>=bufsize) return;
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
+       if(ln>=bufsize) return;
+
+       char* head=k_strdup(tmpbuf);
+       k_channel_send(chan, head, ln, FREE_ON_SENT);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void nexus_file_read(char*  basedir,
+                     char*  filepath,
+                     char*  data,
+                     int    usedmmap,
+                     k_stat kstat,
+                     void*  context)
+{
+       int L=0;
+       if(data) data[kstat.size-1]=0;
+       else     data=k_strdup("");
+       k_hashtable* nex=k_hashtable_new("nexus", 1);
+       if(!ni_get_headers(data, nex, 0)){
+               k_log_err("Corrupt nexus.txt file");
+               k_hashtable_delete(nex);
+               k_free(data);
+               data=k_strdup("");
+               nex=k_hashtable_new("nexus", 1);
+               ni_get_headers(data, nex, 0);
+       }
+
+       char* hostname;
+       nexus_channel=k_hashtable_get_dup(nex, "Nexus-Channel:");
+       hostname     =k_hashtable_get(    nex, "Hostname:");
+
+       if(hostname) ni_hostname_set(hostname);
+
+       if(L) if(nexus_channel) k_log_out("Nexus-Channel: %s", nexus_channel);
+       if(L) if(hostname)      k_log_out("Hostname: %s",      hostname);
+
+       k_hashtable_delete(nex);
+       k_free(data);
+}
+
+void write_nexus(char* hostname)
+{
+       ni_hostname_set(hostname);
+
+       snprintf(tmpbuf, TMPBUFSIZE, "Nexus-Channel: %s\r\n"
+                                    "Hostname:      %s\r\n", nexus_channel,
+                                                             hostname);
+
+       k_file_write(".", "nexus.txt", tmpbuf, strlen(tmpbuf),
+                                      nexus_file_written, 0);
+}
+
+void nexus_file_written(char*  basedir,
+                        char*  filepath,
+                        char*  data,
+                        int    usedmmap,
+                        k_stat kstat,
+                        void*  context)
+{
+       if(!data) k_fatal("Failed to write nexus.txt");
+       else      k_log_out("New nexus.txt written:\n%s", data);
+}
+
+int root_nexus(void)
+{
+       char* hostname=ni_hostname();
+       if(!hostname || strchr(hostname, '-')) return 0;
+       return 1;
+}
+
+void listen_http(void)
+{
+       char* chanm="|nip-server|-|8081|-|";
+       k_channel_connect_name(chanm, connection_readable,
+                                     connection_writable);
+}
+
+void listen_nexus(void)
+{
+       char* chanm="|nip-server|-|7747|-|";
+       k_channel_connect_name(chanm, connection_readable,
+                                     connection_writable);
+}
+
+void connect_to_nexus(void)
+{
+       if(nexus_channel){
+               k_channel_connect_name(nexus_channel, connection_readable,
+                                                     connection_writable);
+       }
+       else k_log_out("discovery of nexus not implemented yet!");
+}
+
+void ping_this(void* arg, char* key, void* val)
+{
+       k_hashtable* channelspinged=arg;
+       char*        chanm=val;
+
+       if(strncmp(chanm, "nip-client", 11)     ) return;
+       if(k_hashtable_get(channelspinged, chanm)) return;
+       k_hashtable_set(channelspinged, chanm, chanm);
+
+       k_channel* chan=k_channel_get_name(chanm);
+       //k_log_out("ping_this: host %s channel %s got=%p", key, chanm, chan);
+
+       if(!chan) k_channel_connect_name(chanm, connection_readable,
+                                               connection_writable);
+
+       int pingtodeath=0;
+       if(chan && pingtodeath) send_ping(chan, "PING OP/0.5", 0);
+}
+
+char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan)
+{
+       if(!ni_hostname()) return 0;
+       unsigned long a=chan->clientip.s_addr;
+       #define IPQUAD(a) \
+               ((unsigned char *)&a)[0], \
+               ((unsigned char *)&a)[1], \
+               ((unsigned char *)&a)[2], \
+               ((unsigned char *)&a)[3]
+       snprintf(tmpbuf, TMPBUFSIZE, "%s-%02x%02x%02x%02x.%d",
+                              ni_hostname(), IPQUAD(a), 7747);
+       if(0) k_log_out("generated new hostname: %s\n", tmpbuf);
+       return k_strdup(tmpbuf);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void set_channel_for(char* host, char* chanm)
+{
+       k_hashtable_put_dup(chans_for_host, host, chanm);
+}
+
+void show_np(void)
+{
+       k_log_out("-------- channel for host ---------------");
+       k_hashtable_apply(chans_for_host,  show_list, 0);
+       k_channel_show_all();
+}
+
+void show_list(void* arg, char* key, void* val)
+{
+       char* chanm=val;
+       k_log_out("%s %s", key, chanm);
+}
+
+void generate_random(void)
+{
+       time_t t=time(0);
+       short r;
+       k_random_bytes((char*)&r, sizeof(r));
+       unsigned char r1=(t >>24) & 255;
+       unsigned char r2=(t >>16) & 255;
+       unsigned char r3=(t >> 8) & 255;
+       unsigned char r4=(t     ) & 255;
+       unsigned char r5=(r >> 8) & 255;
+       unsigned char r6=(r     ) & 255;
+       snprintf(tmpbuf, TMPBUFSIZE, "%02x-%02x-%02x-%02x-%02x-%02x",
+                                     r1, r2, r3, r4, r5, r6);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
diff --git a/src/drivers/ot/mid/mid.c b/src/drivers/ot/mid/mid.c
new file mode 100644 (file)
index 0000000..b27b24a
--- /dev/null
@@ -0,0 +1,408 @@
+
+/* -------------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -------------------------------------------------------------------------- */
+
+#define WINDOW_WIDTH  640
+#define WINDOW_HEIGHT 480
+
+#define POS_ARRAY      0
+#define NORMAL_ARRAY   1
+#define TEXCOORD_ARRAY 2
+
+#define TEX_SIZE 128
+
+/* -------------------------------------------------------------------------- */
+
+static GLfloat xco=   0;
+static GLfloat yco=   1;
+static GLfloat zco= -35;
+static GLfloat view_rotx=0.0, view_roty=0.0, view_rotz=0.0;
+static int     shift=0;
+
+GLuint       program;
+GLuint       texture;
+GLuint       vbo;
+unsigned int numberOfVertices;
+unsigned int posStep;
+unsigned int normStep;
+unsigned int tcStep;
+unsigned int stride;
+float        angle=0.0;
+float        viewAngle = 0.0;
+
+/* -------------------------------------------------------------------------- */
+
+static int  handles_resource(char* name);
+static void sync_resource(ni_resource* res);
+static void init_gl(void);
+static void reshape(int width, int height);
+static void draw(void);
+static void key(unsigned char k, int down);
+
+static int  useTheProgram();
+static int  setUpTnL();
+static int  drawStuff(int width, int height);
+
+/* -------------------------------------------------------------------------- */
+
+EXPORT int mid_module_loaded(void)
+{
+    ni_register_driver("mid", handles_resource, sync_resource);
+
+    init_gl();
+
+    k_gl_register_reshape(reshape);
+    k_gl_register_draw(draw);
+    k_gl_register_key(key);
+
+    k_log_out("MID Driver initialised");
+
+    return 1;
+}
+
+EXPORT int mid_module_event(void* data)
+{
+    k_log_out("MID got event: %p", data);
+    ni_event* evt=data;
+    ni_event_delete(evt);
+    return 1;
+}
+
+EXPORT int mid_module_tick(void)
+{
+    if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
+    return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+    return 0;
+}
+
+void sync_resource(ni_resource* res)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+void init_gl(void)
+{
+    if(!useTheProgram()) k_gl_end();
+    if(!setUpTnL())      k_gl_end();
+}
+
+void reshape(int width, int height)
+{
+}
+
+void draw(void)
+{
+    if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
+}
+
+#define SHIFT 0
+void key(unsigned char k, int down)
+{
+    if(k == 113) viewAngle += 0.1;
+    if(k == 114) viewAngle -= 0.1;
+
+    if(k==SHIFT &&  down){ shift=1; return; }
+    if(k==SHIFT && !down){ shift=0; return; }
+    if(!down) return;
+
+    if(shift) k-=('a'-'A');
+
+    float speed=0.25;
+    switch (k) {
+    case 'H':
+        xco-=speed*(float)sin((view_roty-90)*3.14/180);
+        zco+=speed*(float)cos((view_roty-90)*3.14/180);
+        if(xco< -35) xco= -35;
+        if(xco>  35) xco=  35;
+        if(zco< -35) zco= -35;
+        if(zco>  35) zco=  35;
+    break;
+    case 'L':
+        xco+=speed*(float)sin((view_roty-90)*3.14/180);
+        zco-=speed*(float)cos((view_roty-90)*3.14/180);
+        if(xco< -35) xco= -35;
+        if(xco>  35) xco=  35;
+        if(zco< -35) zco= -35;
+        if(zco>  35) zco=  35;
+    break;
+    case 'i':
+        xco-=speed*(float)sin(view_roty*3.14/180);
+        zco+=speed*(float)cos(view_roty*3.14/180);
+        if(xco< -35) xco= -35;
+        if(xco>  35) xco=  35;
+        if(zco< -35) zco= -35;
+        if(zco>  35) zco=  35;
+    break;
+    case 'o':
+        xco+=speed*(float)sin(view_roty*3.14/180);
+        zco-=speed*(float)cos(view_roty*3.14/180);
+        if(xco< -35) xco= -35;
+        if(xco>  35) xco=  35;
+        if(zco< -35) zco= -35;
+        if(zco>  35) zco=  35;
+    break;
+    case 'j':
+        yco-=speed;
+        if(yco< 0.2) yco= 0.2;
+    break;
+    case 'k':
+        yco+=speed;
+    break;
+    case 'l':
+        view_roty += speed*20;
+    break;
+    case 'h':
+        view_roty -= speed*20;
+    break;
+    case 'J':
+        view_rotx += 2.0;
+    break;
+    case 'K':
+        view_rotx -= 2.0;
+    break;
+    case 'z':
+        view_rotz += 2.0;
+    break;
+    case 'Z':
+        view_rotz -= 2.0;
+    break;
+    default:
+    return;
+    }
+    draw();
+}
+
+/* ------------------------------------------------------------- */
+
+GLuint isShaderError(GLuint thing)
+{
+    GLint isShader = glIsShader(thing);
+
+    GLint ok;
+    if(isShader){
+        glGetShaderiv(thing, GL_COMPILE_STATUS, &ok);
+    }else{
+        glGetProgramiv(thing, GL_LINK_STATUS, &ok);
+    }
+    if(ok) return 0;
+
+    GLint infoLen=0;
+    if(isShader){
+        glGetShaderiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
+    }else{
+        glGetProgramiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
+    }
+    if(infoLen){
+         char* infoLog = malloc(sizeof(char)*infoLen);
+         if(isShader){
+              glGetShaderInfoLog(thing, infoLen, NULL, infoLog);
+         }else{
+              glGetProgramInfoLog(thing, infoLen, NULL, infoLog);
+         }
+         printf("%s: %s\n", isShader? "Shader compile": "Program link", infoLog);
+         free(infoLog);
+    }
+    return 1;
+}
+
+char* file2string(const char *path)
+{
+    FILE *fd;
+    long len, r;
+    char *str;
+    if(!(fd=fopen(path, "r"))) {
+        fprintf(stderr, "Can't open file '%s' for reading\n", path);
+        return NULL;
+    }
+    fseek(fd, 0, SEEK_END);
+    len = ftell(fd);
+    fseek(fd, 0, SEEK_SET);
+    if(!(str=malloc(len*sizeof(char)))) {
+        fprintf(stderr, "Can't malloc space for '%s'\n", path);
+        return NULL;
+    }
+    r = fread(str, sizeof(char), len, fd);
+    str[r-1] = '\0';
+    fclose(fd);
+    return str;
+}
+
+/* ------------------------------------------------------------- */
+
+int useTheProgram()
+{
+    const char *vsSource = file2string("tnl.vert");
+    const char *fsSource = file2string("tnl.frag");
+
+    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(vs, 1, &vsSource, NULL);
+    glCompileShader(vs);
+    if(isShaderError(vs)) return 0;
+    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(fs, 1, &fsSource, NULL);
+    glCompileShader(fs);
+    if(isShaderError(fs)) return 0;
+    free((void*)vsSource);
+    free((void*)fsSource);
+    program = glCreateProgram();
+    glAttachShader(program, vs);
+    glAttachShader(program, fs);
+
+    glBindAttribLocation(program, POS_ARRAY,      "vertPos");
+    glBindAttribLocation(program, NORMAL_ARRAY,   "vertNormal");
+    /* vertNormal and vertTexCoord don't need to be bound here.. ? */
+    glBindAttribLocation(program, TEXCOORD_ARRAY, "vertTexCoord");
+
+    glLinkProgram(program);
+    if(isShaderError(program)) return 0;
+
+    glUseProgram(program);
+
+    glUniform3f(glGetUniformLocation(program, "frameLightDirection"), 1.0, 0.0, 1.0);
+    glUniform1i(glGetUniformLocation(program, "texture"), 0); /* 0 ?? */
+
+    return 1;
+}
+
+int setUpTnL()
+{
+    glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
+
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+
+    GLuint* td = malloc(sizeof(GLuint)*TEX_SIZE*TEX_SIZE);
+    int i,j;
+    for(i=0; i<TEX_SIZE; i++)
+    for(j=0; j<TEX_SIZE; j++) {
+        GLuint col = (255L<<24) + ((255L-j*2)<<16) + ((255L-i)<<8) + (255L-i*2);
+        if ( ((i*j)/8) % 2 ) col = (GLuint) (255L<<24) + (255L<<16) + (0L<<8) + (255L);
+        td[j*TEX_SIZE+i] = col;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, td);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+    free(td);
+
+    GLfloat trivertices[] = {
+                             -0.4f,-0.4f,0.4f,  // Pos
+                              0.0f,0.0f,1.0f,   // Normal
+                              0.0f,0.0f,        // TexCoord
+
+                              0.4f,-0.0f,0.0f,  // Pos
+                              0.0f,0.0f,1.0f,   // Normal
+                              1.0f,0.0f,        // TexCoord
+
+                              0.0f,0.4f,0.4f,   // Pos
+                              0.5f,0.5f,0.5f,   // Normal
+                              0.5f,1.0f,        // TexCoord
+
+                              0.4f,0.0f,0.4f,   // Pos
+                              0.5f,0.5f,0.5f,   // Normal
+                              0.5f,0.0f,        // TexCoord
+
+                              0.4f,0.4f,0.4f,   // Pos
+                              0.0f,0.0f,1.0f,   // Normal
+                              0.0f,0.0f,        // TexCoord
+
+    };
+
+    numberOfVertices = 4;
+    posStep  = 3 * sizeof(GLfloat);
+    normStep = 3 * sizeof(GLfloat);
+    tcStep   = 2 * sizeof(GLfloat);
+    stride = posStep + normStep + tcStep;
+
+    glGenBuffers(1, &vbo);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    glBufferData(GL_ARRAY_BUFFER, numberOfVertices * stride, trivertices, GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+    return 1;
+}
+
+int drawStuff(int width, int height)
+{
+    glViewport(0, 0, width, height);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    float TransRotScaleVerticeMatrix[] = {
+        cos(angle),  0, sin(angle), 0,
+        0,           1, 0,          0,
+        -sin(angle), 0, cos(angle), 0,
+        0,           0, 0,          1
+    };
+
+    float ModelViewProjectionMatrix[] = {
+        cos(viewAngle),  0, sin(viewAngle), 0,
+        0,               1, 0,              0,
+        -sin(viewAngle), 0, cos(viewAngle), 0,
+        0,               0, 0,              1
+    };
+
+    float TransRotScaleNormalMatrix[] = {
+        cos(angle),   0,   sin(angle),
+        0,            1,   0,
+        -sin(angle),  0,   cos(angle)
+    };
+
+    glUniformMatrix4fv(glGetUniformLocation(program, "frameTRSV"), 1, GL_FALSE, TransRotScaleVerticeMatrix);
+    glUniformMatrix4fv(glGetUniformLocation(program, "frameMVP"),  1, GL_FALSE, ModelViewProjectionMatrix);
+    glUniformMatrix3fv(glGetUniformLocation(program, "frameTRSN"), 1, GL_FALSE, TransRotScaleNormalMatrix);
+
+
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+    glEnableVertexAttribArray(POS_ARRAY);
+    glVertexAttribPointer(POS_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, 0);
+
+    glEnableVertexAttribArray(NORMAL_ARRAY);
+    glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, (void*)posStep  );
+
+    glEnableVertexAttribArray(TEXCOORD_ARRAY);
+    glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, stride, (void*)(posStep + normStep) );
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfVertices);
+
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+    k_gl_swap_buffers();
+
+    angle += .007f;
+
+    return 1;
+}
+
+void deleteStuff(){
+    glDeleteTextures(1, &texture);
+    glDeleteBuffers(1, &vbo);
+    glDeleteProgram(program);
+/*  glDeleteShader();
+    glDeleteShader();*/
+}
+/* ------------------------------------------------------------- */
+
+
+
diff --git a/src/drivers/ot/test/teston.c b/src/drivers/ot/test/teston.c
new file mode 100644 (file)
index 0000000..583f3b3
--- /dev/null
@@ -0,0 +1,149 @@
+
+/* -------------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -------------------------------------------------------------------------- */
+
+static int  handles_resource(char* name);
+static void sync_resource(ni_resource* res);
+
+static void start_tests(void);
+static void running_tests(ni_event* evt);
+
+static void test_state(n_object* o, char* os, char* uid, char* cont);
+
+/* -------------------------------------------------------------------------- */
+
+EXPORT int teston_module_loaded(void)
+{
+    ni_register_driver("teston", handles_resource, sync_resource);
+
+    k_log_out("Test ON Driver initialised");
+
+    start_tests();
+
+    return 1;
+}
+
+EXPORT int teston_module_event(void* data)
+{
+    ni_event* evt=data;
+
+    running_tests(evt);
+
+    ni_event_delete(evt);
+    return 1;
+}
+
+EXPORT int teston_module_tick(void)
+{
+    return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+    return 1;
+}
+
+void sync_resource(ni_resource* res)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ - object.create .update .commit .rollback (auto inc version #?)
+ - object.see - may return empty so wait for ..
+ - seestate(object) - state asked for /or/ object is subscribing
+ */
+void start_tests(void)
+{
+    k_log_out("Creating o11111");
+
+    char* o11111s = "UID: 11111-4141a\n"
+                    "\n"
+                    "This: is one content\n";
+
+    n_object* o11111 = n_object_new(o11111s);
+
+    test_state(o11111, o11111s, "11111-4141a", "is one content");
+
+    k_log_out("Committing o11111");
+
+    n_commit(o11111);
+
+    k_log_out("Creating o22222");
+
+    char* o22222s = "UID: 22222-ef990\n"
+                    "\n"
+                    "This: is two content\n";
+
+    n_object* o22222 = n_object_new(o22222s);
+
+    test_state(o22222, o22222s, "22222-ef990", "is two content");
+
+    n_object* o2 = n_see(o11111, "22222-ef990");
+
+    k_assert(!o2, "Object 2 has not been committed yet, but Object 1 can see it:\n%s\n", n_to_string(o2));
+
+    n_commit(o22222);
+
+    o2 = n_see(o11111, "22222-ef990");
+
+    k_assert(o2!=0, "Object 2 has been committed, but can't be seen by Object 1");
+
+    test_state(o2, o22222s, "22222-ef990", "is two content");
+
+    n_object* o3 = n_see(o22222, "33333-18bbc");
+
+    k_assert(!o3, "Object 3 has not been created yet, but Object 2 can see it:\n%s", n_to_string(o3));
+}
+
+void running_tests(ni_event* evt)
+{
+    char* o33333s = 
+            "UID: 33333-18bbc\n"
+            "\n"
+            "This: is three content\n";
+
+    n_object* o33333 = n_object_new(o33333s);
+
+    n_commit(o33333);
+
+}
+
+/* -------------------------------------------------------------------------- */
+
+void test_state(n_object* o, char* os, char* uid, char* cont)
+{
+    char* c;
+
+    k_log_out("Checking %s", uid);
+
+    c=n_to_string(o);
+    k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
+
+    c=n_uid(o);
+    k_assert(c && !strcmp(c, uid), "UID was %s in n_uid",  c? c: "null");
+
+    c=n_header(o, "UID");
+    k_assert(c && !strcmp(c, uid), "UID was %s in n_header",  c? c: "null");
+
+    c=k_hashtable_get(n_headers(o), "UID");
+    k_assert(c && !strcmp(c, uid), "UID was %s in hash get",  c? c: "null");
+
+    c=k_hashtable_get(n_content(o), "This");
+    k_assert(c && !strcmp(c, cont), "Content was %s", c? c: "null");
+
+    c=n_to_string(o);
+    k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+
diff --git a/src/include/ni.h b/src/include/ni.h
deleted file mode 100644 (file)
index 7916190..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-
-#ifndef ni_H
-#define ni_H
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct n_object{
-       k_hashtable* headers;
-       k_hashtable* content;
-} n_object;
-
-PUBLIC n_object*    n_object_new(char* s);
-PUBLIC void         n_commit(n_object* o);
-PUBLIC n_object*    n_see(n_object* o, char* uid);
-PUBLIC char*        n_to_string(n_object* o);
-PUBLIC char*        n_uid(n_object* o);
-PUBLIC char*        n_header(n_object* o, char* name);
-PUBLIC k_hashtable* n_headers(n_object* o);
-PUBLIC k_hashtable* n_content(n_object* o);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC char* ni_hostname(void);
-PUBLIC void  ni_hostname_set(char* name);
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct ni_resource{
-       char*        uri;
-       k_hashtable* ent_head;
-       void*        entity;
-} ni_resource;
-
-PUBLIC ni_resource* ni_resource_new(char*        uri,
-                                    k_hashtable* ent_head,
-                                    char*        entity);
-PUBLIC ni_resource* ni_resource_dup(   ni_resource* res);
-PUBLIC void         ni_resource_delete(ni_resource* res);
-PUBLIC void         ni_resource_show(  ni_resource* res, char* text);
-PUBLIC ni_resource* ni_resource_get(char* uri);
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct ni_event{
-       char*        uri;
-       k_hashtable* evt_head;
-       k_hashtable* ent_head;
-       void*        entity;
-} ni_event;
-
-PUBLIC ni_event* ni_event_new(char*        uri,
-                              k_hashtable* evt_head,
-                              k_hashtable* ent_head,
-                              char*        entity);
-PUBLIC ni_event* ni_event_dup(   ni_event* res);
-PUBLIC void      ni_event_delete(ni_event* res);
-PUBLIC void      ni_event_show(  ni_event* res, char* text);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC ni_event* ni_res_to_evt(ni_resource* res);
-
-/* -------------------------------------------------------------------------- */
-
-typedef int  (*ni_handles_resource)(char*);
-typedef void (*ni_sync_resource   )(ni_resource*);
-
-PUBLIC void ni_register_driver(char*               name,
-                               ni_handles_resource handles_resource,
-                               ni_sync_resource    sync_resource);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC ni_event* ni_get_request_headers( char* header);
-PUBLIC ni_event* ni_get_response_headers(char* header);
-PUBLIC char*     ni_get_headers( char* header, k_hashtable*, k_hashtable*);
-PUBLIC void      ni_fix_http_headers(k_hashtable* ent_head);
-PUBLIC void      ni_fix_ni_headers(k_hashtable* ent_head, int methead);
-PUBLIC void      ni_response(ni_event* evt,
-                             char*      to,
-                             char*      method,
-                             char*      protocol,
-                             char*      connection,
-                             k_channel* chan);
-PUBLIC void      ni_request(ni_event* evt,
-                            char*      to,
-                            char*      method,
-                            k_channel* chan);
-
-/* -------------------------------------------------------------------------- */
-
-#endif
-
diff --git a/src/include/notification.h b/src/include/notification.h
new file mode 100644 (file)
index 0000000..7916190
--- /dev/null
@@ -0,0 +1,93 @@
+
+#ifndef ni_H
+#define ni_H
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct n_object{
+       k_hashtable* headers;
+       k_hashtable* content;
+} n_object;
+
+PUBLIC n_object*    n_object_new(char* s);
+PUBLIC void         n_commit(n_object* o);
+PUBLIC n_object*    n_see(n_object* o, char* uid);
+PUBLIC char*        n_to_string(n_object* o);
+PUBLIC char*        n_uid(n_object* o);
+PUBLIC char*        n_header(n_object* o, char* name);
+PUBLIC k_hashtable* n_headers(n_object* o);
+PUBLIC k_hashtable* n_content(n_object* o);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC char* ni_hostname(void);
+PUBLIC void  ni_hostname_set(char* name);
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct ni_resource{
+       char*        uri;
+       k_hashtable* ent_head;
+       void*        entity;
+} ni_resource;
+
+PUBLIC ni_resource* ni_resource_new(char*        uri,
+                                    k_hashtable* ent_head,
+                                    char*        entity);
+PUBLIC ni_resource* ni_resource_dup(   ni_resource* res);
+PUBLIC void         ni_resource_delete(ni_resource* res);
+PUBLIC void         ni_resource_show(  ni_resource* res, char* text);
+PUBLIC ni_resource* ni_resource_get(char* uri);
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct ni_event{
+       char*        uri;
+       k_hashtable* evt_head;
+       k_hashtable* ent_head;
+       void*        entity;
+} ni_event;
+
+PUBLIC ni_event* ni_event_new(char*        uri,
+                              k_hashtable* evt_head,
+                              k_hashtable* ent_head,
+                              char*        entity);
+PUBLIC ni_event* ni_event_dup(   ni_event* res);
+PUBLIC void      ni_event_delete(ni_event* res);
+PUBLIC void      ni_event_show(  ni_event* res, char* text);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC ni_event* ni_res_to_evt(ni_resource* res);
+
+/* -------------------------------------------------------------------------- */
+
+typedef int  (*ni_handles_resource)(char*);
+typedef void (*ni_sync_resource   )(ni_resource*);
+
+PUBLIC void ni_register_driver(char*               name,
+                               ni_handles_resource handles_resource,
+                               ni_sync_resource    sync_resource);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC ni_event* ni_get_request_headers( char* header);
+PUBLIC ni_event* ni_get_response_headers(char* header);
+PUBLIC char*     ni_get_headers( char* header, k_hashtable*, k_hashtable*);
+PUBLIC void      ni_fix_http_headers(k_hashtable* ent_head);
+PUBLIC void      ni_fix_ni_headers(k_hashtable* ent_head, int methead);
+PUBLIC void      ni_response(ni_event* evt,
+                             char*      to,
+                             char*      method,
+                             char*      protocol,
+                             char*      connection,
+                             k_channel* chan);
+PUBLIC void      ni_request(ni_event* evt,
+                            char*      to,
+                            char*      method,
+                            k_channel* chan);
+
+/* -------------------------------------------------------------------------- */
+
+#endif
+
diff --git a/src/ni/headers.c b/src/ni/headers.c
deleted file mode 100644 (file)
index 391fcc2..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#undef  PUBLIC
-#define PUBLIC EXPORT
-#include <ni.h>
-
-/* -}{---- ------------------------------------------------------------------ */
-
-static k_hashtable* entity_headers;
-
-/* -}{---- ------------------------------------------------------------------ */
-
-#define TMPBUFSIZE  4096
-static char         tmpbuf[TMPBUFSIZE];
-
-/* -}{----------------------------------------------------------------------- */
-
-static char* get_request( char* header, k_hashtable*, k_hashtable*);
-static char* get_response(char* header, k_hashtable*, k_hashtable*);
-static char* get_val(char** atp);
-static char* end_of_val(char* at);
-static void  fix_keepalive(k_hashtable* evt_head);
-static void  fix_cache_control(k_hashtable* ent_head);
-static void  fix_uri(k_hashtable* ent_head);
-static void  fix_subscribe(k_hashtable*, k_hashtable*);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define WHITESPACEH  " \t"
-#define WHITESPACEV  "\012\015"
-#define WHITESPACE   WHITESPACEH WHITESPACEV
-
-EXPORT ni_event* ni_get_request_headers(char* header)
-{
-       k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1);
-       k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1);
-       k_hashtable_put(ent_head, "", header);
-
-       char* h=get_request(header, evt_head, ent_head);
-       if(!h){
-               k_hashtable_delete(evt_head);
-               k_hashtable_delete(ent_head);
-               return 0;
-       }
-
-       h=ni_get_headers(h, evt_head, ent_head);
-       if(!h){
-               k_hashtable_delete(evt_head);
-               k_hashtable_delete(ent_head);
-               return 0;
-       }
-
-       fix_keepalive(evt_head);
-       fix_cache_control(ent_head);
-       fix_uri(ent_head);
-       fix_subscribe(evt_head, ent_head);
-
-       ni_event* evq=ni_event_new(0, evt_head, ent_head, 0);
-
-       return evq;
-}
-
-EXPORT ni_event* ni_get_response_headers(char* header)
-{
-       k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1);
-       k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1);
-       k_hashtable_put(ent_head, "", header);
-
-       char* h=get_response(header, evt_head, ent_head);
-       if(!h){
-               k_hashtable_delete(evt_head);
-               k_hashtable_delete(ent_head);
-               return 0;
-       }
-
-       h=ni_get_headers(h, evt_head, ent_head);
-       if(!h){
-               k_hashtable_delete(evt_head);
-               k_hashtable_delete(ent_head);
-               return 0;
-       }
-
-       ni_event* evt=ni_event_new(0, evt_head, ent_head, 0);
-
-       return evt;
-}
-
-EXPORT char* ni_get_headers(char*        header,
-                             k_hashtable* evt_head,
-                             k_hashtable* ent_head)
-{
-       char* at=header;
-       char* tag;
-       char* val;
-       while(*at){
-
-               tag=at;
-               at=strpbrk(at, WHITESPACE);
-               if(!at || at==tag) return 0;
-               char* e=at;
-               val=get_val(&at);
-               *e=0;
-
-               if(strlen(val) > 2048) return 0;
-
-               k_hashtable* h;
-               h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head;
-               if(h){
-                       char* old=k_hashtable_get(h, tag);
-                       if(!old)  k_hashtable_set(h, tag, val);
-               }
-       }
-       return at;
-}
-
-EXPORT void ni_fix_http_headers(k_hashtable* ent_head)
-{
-       if(k_hashtable_is(ent_head, "Status:", "260")){
-               char* crn=k_hashtable_get(ent_head,  "Content-Range:");
-               char* clg=k_hashtable_get(ent_head,  "Content-Length-Given:");
-               if(crn || clg){
-                       k_hashtable_set(ent_head, "Status:", "206");
-                       k_hashtable_set(ent_head, "Status-Text:", "Partial Content");
-               }
-               else{
-                       k_hashtable_set(ent_head, "Status:", "200");
-                       k_hashtable_set(ent_head, "Status-Text:", "OK");
-               }
-       }
-       k_hashtable_remove(ent_head, "URI:");
-       k_hashtable_remove(ent_head, "Method:");
-       k_hashtable_remove(ent_head, "From:");
-       k_hashtable_remove(ent_head, "Content-Length-Given:");
-       k_hashtable_remove(ent_head, "Last-Modified-Epoch:");
-
-       char* cc=k_hashtable_get(ent_head, "Cache-Control:");
-       if(cc && strstr(cc, "no-cache")){
-               k_hashtable_set(ent_head, "Pragma:", "no-cache");
-       }
-}
-
-EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead)
-{
-       if(methead && (k_hashtable_is(ent_head, "Status:", "200") ||
-                      k_hashtable_is(ent_head, "Status:", "206")   )){
-
-               k_hashtable_set(ent_head, "Status:", "260");
-               k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
-       }
-       k_hashtable_remove(ent_head, "Method:");
-       k_hashtable_remove(ent_head, "Sub-To:");
-       k_hashtable_remove(ent_head, "Via:");
-       k_hashtable_set(   ent_head, "From:", ni_hostname());
-
-       char* uri=k_hashtable_get(ent_head, "URI:");
-       if(*uri=='.'){
-               snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2);
-               k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
-       }
-}
-
-EXPORT void ni_response(ni_event* evt,
-                         char*      to,
-                         char*      method,
-                         char*      protocol,
-                         char*      connection,
-                         k_channel* chan)
-{
-       int L=0;
-       snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0));
-       k_hashtable_put_dup(evt->evt_head, "Date:",       tmpbuf);
-       k_hashtable_set(    evt->evt_head, "Server:",     k_version);
-       if(connection)
-       k_hashtable_put_dup(evt->evt_head, "Connection:", connection);
-
-       int   status    =k_hashtable_get_int(evt->ent_head, "Status:");
-       char* statustext=k_hashtable_get(    evt->ent_head, "Status-Text:");
-       int   datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:");
-       int   constant  =k_hashtable_is(     evt->ent_head, "CUX:", "C");
-
-       char* buf    =tmpbuf;
-       int   bufsize=TMPBUFSIZE;
-       int   ln=0;
-
-       ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF, 
-                                         protocol, status, statustext);
-       if(ln>=bufsize) return;
-
-       static char* exheaders[]={ "Status:", "Status-Text:",
-                                  "Protocol:", "CUX:", 0 };
-
-       ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders);
-       if(ln>=bufsize) return;
-
-       ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders);
-       if(ln>=bufsize) return;
-
-       ln+=snprintf(buf+ln, bufsize-ln, CRLF);
-       if(ln>=bufsize) return;
-
-       char* head=k_strdup(buf);
-       if(L) k_log_out("Actual response headers:\n%s", head);
-       k_channel_send(chan, head, ln, FREE_ON_SENT);
-
-       if(evt->entity && datalength){
-               k_channel_send(chan, evt->entity, datalength, !constant);
-       }
-       else{
-               datalength=0;
-               if(!constant) k_free(evt->entity);
-       }
-       k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength);
-}
-
-EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan)
-{
-       k_hashtable* sub=evt->ent_head;
-
-       int ln=0;
-       int bufsize=TMPBUFSIZE;
-
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s ni/0.5" CRLF, method, to);
-       if(ln>=bufsize) return;
-
-       ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln);
-       if(ln>=bufsize) return;
-
-       ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
-       if(ln>=bufsize) return;
-
-       char* head=k_strdup(tmpbuf);
-       if(0) k_log_out("Actual request headers:\n%s", head);
-       k_channel_send(chan, head, ln, FREE_ON_SENT);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
-{
-       char* at=header;
-       char* method=at;
-       at=strpbrk(at, WHITESPACEH);
-       if(!at) return 0;
-       *at++=0;
-
-       k_hashtable_set(ent_head, "Method:", method);
-
-       char* file=0;
-       char* host=0;
-       if(strcmp(method, "PING")){
-
-               at+=strspn(at, WHITESPACEH);
-               file=at;
-               at=strpbrk(at, WHITESPACEH);
-               if(!at) return 0;
-               *at++=0;
-               if(strlen(file) > 1024 ) return 0;
-
-               if(!strncmp(file, "http://", 7)){
-                       char* s=file+7;
-                       if(!*s || *s=='/') return 0;
-                       char* e=strchr(s, '/');
-                       if(!e) return 0;
-                       host=s;
-                       *e++=0;
-                       file=e;
-               }
-               else
-               if(*file=='/') file++;
-               else return 0;
-       
-               if(*file=='/'){
-                       char* s=file+1;
-                       if(!*s || *s=='/') return 0;
-                       char* e=strchr(s, '/');
-                       if(!e) return 0;
-                       host=s;
-                       *e++=0;
-                       file=e;
-               }
-       }
-       if(file) k_hashtable_set(evt_head, "File:", file);
-       if(host) k_hashtable_set(evt_head, "Host:", host);
-
-       at+=strspn(at, WHITESPACEH);
-       char* protocol=at;
-       at=strpbrk(at, WHITESPACE);
-       if(!at) at=protocol+strlen(protocol);
-       else   *at++=0;
-
-       k_hashtable_set(evt_head, "Protocol:", protocol);
-
-       at+=strspn(at, WHITESPACE);
-       return at;
-}
-
-char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
-{
-       char* at=header;
-       char* protocol=at;
-       at=strpbrk(at, WHITESPACEH);
-       if(!at) return 0;
-       *at++=0;
-
-       k_hashtable_set(evt_head, "Protocol:", protocol);
-
-       at+=strspn(at, WHITESPACEH);
-       char* status=at;
-       at=strpbrk(at, WHITESPACEH);
-       if(!at) return 0;
-       *at++=0;
-
-       at+=strspn(at, WHITESPACEH);
-       char* statustext=at;
-       at=strpbrk(at, WHITESPACEV);
-       if(!at) return 0;
-       *at++=0;
-
-       k_hashtable_set(ent_head, "Status:",      status);
-       k_hashtable_set(ent_head, "Status-Text:", statustext);
-
-       at+=strspn(at, WHITESPACE);
-       return at;
-}
-
-char* get_val(char** atp)
-{
-       char* at=*atp;
-       char* val=at;
-
-       val+=strspn(val, WHITESPACEH);
-       val+=strspn(val, WHITESPACEV);
-
-       char* eov=end_of_val(at);
-       if(eov<val) val=eov;
-       if(*eov) *eov++=0;
-
-       *atp=eov+strspn(eov, WHITESPACEV);
-       return val;
-}
-
-char* end_of_val(char* at)
-{
-       char* eov;
-       do{
-               char* v=strpbrk(at, WHITESPACEV);
-               if(!v) return at+strlen(at);
-               eov=v;
-               at=v+strspn(v, WHITESPACEV);
-
-       }while(strspn(at, WHITESPACEH));
-
-       return eov;
-}
-
-void fix_keepalive(k_hashtable* evt_head)
-{
-       int keepalive=0;
-       int is11=k_hashtable_is( evt_head, "Protocol:",   "HTTP/1.1");
-       int isps=k_hashtable_isn(evt_head, "Protocol:",   "ni/", 4);
-       int iska=k_hashtable_isi(evt_head, "Connection:", "Keep-Alive");
-       int iscl=k_hashtable_isi(evt_head, "Connection:", "close");
-       if((!is11 && iska) || (is11 && !iscl) || isps){
-               keepalive=1;
-       }
-       if(0) k_log_out("is11=%d iska=%d iscl=%d isps=%d ka=%d",
-                        is11,   iska,   iscl,   isps,   keepalive);
-       k_hashtable_set(evt_head, "Connection:", 
-                                 keepalive? "Keep-Alive": "close");
-}
-
-void fix_cache_control(k_hashtable* ent_head)
-{
-       char* cachec=k_hashtable_get(    ent_head, "Cache-Control:");
-       char* pragma=k_hashtable_extract(ent_head, "Pragma:");
-       if(!cachec && pragma && strstr(pragma, "no-cache")){
-               k_hashtable_set(         ent_head, "Cache-Control:","no-cache");
-       }
-}
-
-void fix_uri(k_hashtable* ent_head)
-{
-       char* uri=k_hashtable_get(ent_head, "URI:");
-       if(!uri) return;
-       char* nihostname=ni_hostname();
-       int l=strlen(nihostname);
-       if(strncmp(uri, nihostname, l)) return;
-       snprintf(tmpbuf, TMPBUFSIZE, ".%s", uri+l);
-       k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
-}
-
-void fix_subscribe(k_hashtable* evt_head, k_hashtable* ent_head)
-{
-       char* host=k_hashtable_extract(evt_head, "Host:");
-       char* file=k_hashtable_extract(evt_head, "File:");
-       if(host){
-               k_string_url_decode(host);
-               int localhostdns=!strcmp( host, "localhost") ||
-                                !strncmp(host, "localhost:", 10);
-               int localhostni=!strcmp(host, ni_hostname());
-               char* lastdot=strrchr(host, '.');
-               int dotdotnumber=lastdot && atoi(lastdot+1) >0;
-               if(localhostdns || localhostni || dotdotnumber){
-                       host=".";
-               }
-       }
-       else{
-               host=".";
-       }
-       if(file){
-               k_string_url_decode(file);
-               snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file);
-               k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf);
-               k_hashtable_set(    ent_head, "Sub-Type:", "Original");
-       }
-}
-
-void init_headers(void)
-{
-       entity_headers  =k_hashtable_new("Entity Headers", 1);
-
-       k_hashtable_set(entity_headers, "URI:", (void*)1);
-       k_hashtable_set(entity_headers, "From:", (void*)1);
-       k_hashtable_set(entity_headers, "To:", (void*)1);
-       k_hashtable_set(entity_headers, "Via:", (void*)1);
-       k_hashtable_set(entity_headers, "Sub-To:", (void*)1);
-       k_hashtable_set(entity_headers, "Sub-Type:", (void*)1);
-       k_hashtable_set(entity_headers, "Method:", (void*)1);
-       k_hashtable_set(entity_headers, "Status:", (void*)1);
-       k_hashtable_set(entity_headers, "Status-Text:", (void*)1);
-       k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1);
-       k_hashtable_set(entity_headers, "CUX:", (void*)1);
-
-       k_hashtable_set(entity_headers, "Range:", (void*)1);
-       k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1);
-       k_hashtable_set(entity_headers, "If-None-Match:", (void*)1);
-       k_hashtable_set(entity_headers, "Cache-Control:", (void*)1);
-       k_hashtable_set(entity_headers, "Pragma:", (void*)1);
-
-       k_hashtable_set(entity_headers, "Content-Length:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-Type:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-Location:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-MD5:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-Language:", (void*)1);
-       k_hashtable_set(entity_headers, "Content-Range:", (void*)1);
-       k_hashtable_set(entity_headers, "Last-Modified:", (void*)1);
-       k_hashtable_set(entity_headers, "ETag:", (void*)1);
-       k_hashtable_set(entity_headers, "Expires:", (void*)1);
-
-       k_hashtable_set(entity_headers, "Allow:", (void*)1);
-}
-
-void drop_entity_headers(k_hashtable* ent_head)
-{
-       k_hashtable_remove(ent_head, "Content-Length:");
-       k_hashtable_remove(ent_head, "Content-Range:");
-       k_hashtable_remove(ent_head, "Content-Type:");
-       k_hashtable_remove(ent_head, "Content-Encoding:");
-       k_hashtable_remove(ent_head, "Content-Location:");
-       k_hashtable_remove(ent_head, "Last-Modified:");
-#ifdef DO_THESE_ONES_TOO
-       k_hashtable_remove(ent_head, "Allow:");
-       k_hashtable_remove(ent_head, "Content-Language:");
-       k_hashtable_remove(ent_head, "Content-MD5:");
-       k_hashtable_remove(ent_head, "Expires:");
-#endif
-}
-
-void fill_headers(k_hashtable* ent_head,
-                  char*  status,
-                  char*  statustext,
-                  char*  uri,
-                  time_t modifitime,
-                  int    datalength,
-                  char*  mimetype,
-                  char*  encoding,
-                  int    nocache)
-{
-       if(status){
-               k_hashtable_put_dup(ent_head, "Status:",      status);
-               k_hashtable_put_dup(ent_head, "Status-Text:", statustext);
-       }
-       if(uri){
-               k_hashtable_put_dup(ent_head, "URI:", uri);
-       }
-       if(modifitime>=0){
-               snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime));
-               k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf);
-       }
-       if(datalength>=0){
-               snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength);
-               k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf);
-       }
-       if(mimetype){
-               k_hashtable_put_dup(ent_head, "Content-Type:",   mimetype);
-       }
-       if(encoding){
-               k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding);
-       }
-       if(nocache==1){
-               k_hashtable_put_dup(ent_head, "Cache-Control:",
-                                             "no-cache,no-store");
-       }
-       else
-       if(nocache==0){
-               long maxage=31449600;
-               snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage);
-               char* maxages=k_time_to_rfc_relative(maxage);
-               k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf);
-               k_hashtable_put_dup(ent_head, "Expires:", maxages);
-       }
-       else
-       if(nocache== -1){
-               k_hashtable_remove(ent_head, "Cache-Control:");
-               k_hashtable_remove(ent_head, "Expires:");
-       }
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
diff --git a/src/ni/ni.c b/src/ni/ni.c
deleted file mode 100644 (file)
index fae4db1..0000000
+++ /dev/null
@@ -1,824 +0,0 @@
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#undef  PUBLIC
-#define PUBLIC EXPORT
-#include <ni.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 ni_module_loaded(void)
-{
-       resources=k_hashtable_new("Resources", 0);
-
-       init_headers();
-
-       k_log_out("NI initialised");
-       return 1;
-}
-
-EXPORT void ni_module_tick(void)
-{
-}
-
-EXPORT int ni_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, "NI 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, "ni 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 ni:");
-}
-
-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* npdriver;
-static ni_driver* moddriver;
-
-char* handled_by(char* pub)
-{
-       if(moddriver->handles_resource(pub)) return moddriver->name;
-       return "np";
-}
-
-void call_sync_resource(ni_resource* res)
-{
-       if(moddriver->handles_resource(res->uri)) moddriver->sync_resource(res);
-       else                                      npdriver->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, "np")) npdriver=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);
-       }
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-
-
-
diff --git a/src/on/headers.c b/src/on/headers.c
new file mode 100644 (file)
index 0000000..13fc3e0
--- /dev/null
@@ -0,0 +1,523 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#undef  PUBLIC
+#define PUBLIC EXPORT
+#include <notification.h>
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static k_hashtable* entity_headers;
+
+/* -}{---- ------------------------------------------------------------------ */
+
+#define TMPBUFSIZE  4096
+static char         tmpbuf[TMPBUFSIZE];
+
+/* -}{----------------------------------------------------------------------- */
+
+static char* get_request( char* header, k_hashtable*, k_hashtable*);
+static char* get_response(char* header, k_hashtable*, k_hashtable*);
+static char* get_val(char** atp);
+static char* end_of_val(char* at);
+static void  fix_keepalive(k_hashtable* evt_head);
+static void  fix_cache_control(k_hashtable* ent_head);
+static void  fix_uri(k_hashtable* ent_head);
+static void  fix_subscribe(k_hashtable*, k_hashtable*);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define WHITESPACEH  " \t"
+#define WHITESPACEV  "\012\015"
+#define WHITESPACE   WHITESPACEH WHITESPACEV
+
+EXPORT ni_event* ni_get_request_headers(char* header)
+{
+       k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1);
+       k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1);
+       k_hashtable_put(ent_head, "", header);
+
+       char* h=get_request(header, evt_head, ent_head);
+       if(!h){
+               k_hashtable_delete(evt_head);
+               k_hashtable_delete(ent_head);
+               return 0;
+       }
+
+       h=ni_get_headers(h, evt_head, ent_head);
+       if(!h){
+               k_hashtable_delete(evt_head);
+               k_hashtable_delete(ent_head);
+               return 0;
+       }
+
+       fix_keepalive(evt_head);
+       fix_cache_control(ent_head);
+       fix_uri(ent_head);
+       fix_subscribe(evt_head, ent_head);
+
+       ni_event* evq=ni_event_new(0, evt_head, ent_head, 0);
+
+       return evq;
+}
+
+EXPORT ni_event* ni_get_response_headers(char* header)
+{
+       k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1);
+       k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1);
+       k_hashtable_put(ent_head, "", header);
+
+       char* h=get_response(header, evt_head, ent_head);
+       if(!h){
+               k_hashtable_delete(evt_head);
+               k_hashtable_delete(ent_head);
+               return 0;
+       }
+
+       h=ni_get_headers(h, evt_head, ent_head);
+       if(!h){
+               k_hashtable_delete(evt_head);
+               k_hashtable_delete(ent_head);
+               return 0;
+       }
+
+       ni_event* evt=ni_event_new(0, evt_head, ent_head, 0);
+
+       return evt;
+}
+
+EXPORT char* ni_get_headers(char*        header,
+                             k_hashtable* evt_head,
+                             k_hashtable* ent_head)
+{
+       char* at=header;
+       char* tag;
+       char* val;
+       while(*at){
+
+               tag=at;
+               at=strpbrk(at, WHITESPACE);
+               if(!at || at==tag) return 0;
+               char* e=at;
+               val=get_val(&at);
+               *e=0;
+
+               if(strlen(val) > 2048) return 0;
+
+               k_hashtable* h;
+               h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head;
+               if(h){
+                       char* old=k_hashtable_get(h, tag);
+                       if(!old)  k_hashtable_set(h, tag, val);
+               }
+       }
+       return at;
+}
+
+EXPORT void ni_fix_http_headers(k_hashtable* ent_head)
+{
+       if(k_hashtable_is(ent_head, "Status:", "260")){
+               char* crn=k_hashtable_get(ent_head,  "Content-Range:");
+               char* clg=k_hashtable_get(ent_head,  "Content-Length-Given:");
+               if(crn || clg){
+                       k_hashtable_set(ent_head, "Status:", "206");
+                       k_hashtable_set(ent_head, "Status-Text:", "Partial Content");
+               }
+               else{
+                       k_hashtable_set(ent_head, "Status:", "200");
+                       k_hashtable_set(ent_head, "Status-Text:", "OK");
+               }
+       }
+       k_hashtable_remove(ent_head, "URI:");
+       k_hashtable_remove(ent_head, "Method:");
+       k_hashtable_remove(ent_head, "From:");
+       k_hashtable_remove(ent_head, "Content-Length-Given:");
+       k_hashtable_remove(ent_head, "Last-Modified-Epoch:");
+
+       char* cc=k_hashtable_get(ent_head, "Cache-Control:");
+       if(cc && strstr(cc, "no-cache")){
+               k_hashtable_set(ent_head, "Pragma:", "no-cache");
+       }
+}
+
+EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead)
+{
+       if(methead && (k_hashtable_is(ent_head, "Status:", "200") ||
+                      k_hashtable_is(ent_head, "Status:", "206")   )){
+
+               k_hashtable_set(ent_head, "Status:", "260");
+               k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
+       }
+       k_hashtable_remove(ent_head, "Method:");
+       k_hashtable_remove(ent_head, "Sub-To:");
+       k_hashtable_remove(ent_head, "Via:");
+       k_hashtable_set(   ent_head, "From:", ni_hostname());
+
+       char* uri=k_hashtable_get(ent_head, "URI:");
+       if(*uri=='.'){
+               snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2);
+               k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
+       }
+}
+
+EXPORT void ni_response(ni_event* evt,
+                         char*      to,
+                         char*      method,
+                         char*      protocol,
+                         char*      connection,
+                         k_channel* chan)
+{
+       int L=0;
+       snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0));
+       k_hashtable_put_dup(evt->evt_head, "Date:",       tmpbuf);
+       k_hashtable_set(    evt->evt_head, "Server:",     k_version);
+       if(connection)
+       k_hashtable_put_dup(evt->evt_head, "Connection:", connection);
+
+       int   status    =k_hashtable_get_int(evt->ent_head, "Status:");
+       char* statustext=k_hashtable_get(    evt->ent_head, "Status-Text:");
+       int   datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:");
+       int   constant  =k_hashtable_is(     evt->ent_head, "CUX:", "C");
+
+       char* buf    =tmpbuf;
+       int   bufsize=TMPBUFSIZE;
+       int   ln=0;
+
+       ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF, 
+                                         protocol, status, statustext);
+       if(ln>=bufsize) return;
+
+       static char* exheaders[]={ "Status:", "Status-Text:",
+                                  "Protocol:", "CUX:", 0 };
+
+       ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders);
+       if(ln>=bufsize) return;
+
+       ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders);
+       if(ln>=bufsize) return;
+
+       ln+=snprintf(buf+ln, bufsize-ln, CRLF);
+       if(ln>=bufsize) return;
+
+       char* head=k_strdup(buf);
+       if(L) k_log_out("Actual response headers:\n%s", head);
+       k_channel_send(chan, head, ln, FREE_ON_SENT);
+
+       if(evt->entity && datalength){
+               k_channel_send(chan, evt->entity, datalength, !constant);
+       }
+       else{
+               datalength=0;
+               if(!constant) k_free(evt->entity);
+       }
+       k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength);
+}
+
+EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan)
+{
+       k_hashtable* sub=evt->ent_head;
+
+       int ln=0;
+       int bufsize=TMPBUFSIZE;
+
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s OP/0.5" CRLF, method, to);
+       if(ln>=bufsize) return;
+
+       ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln);
+       if(ln>=bufsize) return;
+
+       ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
+       if(ln>=bufsize) return;
+
+       char* head=k_strdup(tmpbuf);
+       if(0) k_log_out("Actual request headers:\n%s", head);
+       k_channel_send(chan, head, ln, FREE_ON_SENT);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
+{
+       char* at=header;
+       char* method=at;
+       at=strpbrk(at, WHITESPACEH);
+       if(!at) return 0;
+       *at++=0;
+
+       k_hashtable_set(ent_head, "Method:", method);
+
+       char* file=0;
+       char* host=0;
+       if(strcmp(method, "PING")){
+
+               at+=strspn(at, WHITESPACEH);
+               file=at;
+               at=strpbrk(at, WHITESPACEH);
+               if(!at) return 0;
+               *at++=0;
+               if(strlen(file) > 1024 ) return 0;
+
+               if(!strncmp(file, "http://", 7)){
+                       char* s=file+7;
+                       if(!*s || *s=='/') return 0;
+                       char* e=strchr(s, '/');
+                       if(!e) return 0;
+                       host=s;
+                       *e++=0;
+                       file=e;
+               }
+               else
+               if(*file=='/') file++;
+               else return 0;
+       
+               if(*file=='/'){
+                       char* s=file+1;
+                       if(!*s || *s=='/') return 0;
+                       char* e=strchr(s, '/');
+                       if(!e) return 0;
+                       host=s;
+                       *e++=0;
+                       file=e;
+               }
+       }
+       if(file) k_hashtable_set(evt_head, "File:", file);
+       if(host) k_hashtable_set(evt_head, "Host:", host);
+
+       at+=strspn(at, WHITESPACEH);
+       char* protocol=at;
+       at=strpbrk(at, WHITESPACE);
+       if(!at) at=protocol+strlen(protocol);
+       else   *at++=0;
+
+       k_hashtable_set(evt_head, "Protocol:", protocol);
+
+       at+=strspn(at, WHITESPACE);
+       return at;
+}
+
+char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
+{
+       char* at=header;
+       char* protocol=at;
+       at=strpbrk(at, WHITESPACEH);
+       if(!at) return 0;
+       *at++=0;
+
+       k_hashtable_set(evt_head, "Protocol:", protocol);
+
+       at+=strspn(at, WHITESPACEH);
+       char* status=at;
+       at=strpbrk(at, WHITESPACEH);
+       if(!at) return 0;
+       *at++=0;
+
+       at+=strspn(at, WHITESPACEH);
+       char* statustext=at;
+       at=strpbrk(at, WHITESPACEV);
+       if(!at) return 0;
+       *at++=0;
+
+       k_hashtable_set(ent_head, "Status:",      status);
+       k_hashtable_set(ent_head, "Status-Text:", statustext);
+
+       at+=strspn(at, WHITESPACE);
+       return at;
+}
+
+char* get_val(char** atp)
+{
+       char* at=*atp;
+       char* val=at;
+
+       val+=strspn(val, WHITESPACEH);
+       val+=strspn(val, WHITESPACEV);
+
+       char* eov=end_of_val(at);
+       if(eov<val) val=eov;
+       if(*eov) *eov++=0;
+
+       *atp=eov+strspn(eov, WHITESPACEV);
+       return val;
+}
+
+char* end_of_val(char* at)
+{
+       char* eov;
+       do{
+               char* v=strpbrk(at, WHITESPACEV);
+               if(!v) return at+strlen(at);
+               eov=v;
+               at=v+strspn(v, WHITESPACEV);
+
+       }while(strspn(at, WHITESPACEH));
+
+       return eov;
+}
+
+void fix_keepalive(k_hashtable* evt_head)
+{
+       int keepalive=0;
+       int is11=k_hashtable_is( evt_head, "Protocol:",   "HTTP/1.1");
+       int isps=k_hashtable_isn(evt_head, "Protocol:",   "OP/", 4);
+       int iska=k_hashtable_isi(evt_head, "Connection:", "Keep-Alive");
+       int iscl=k_hashtable_isi(evt_head, "Connection:", "close");
+       if((!is11 && iska) || (is11 && !iscl) || isps){
+               keepalive=1;
+       }
+       if(0) k_log_out("is11=%d iska=%d iscl=%d isps=%d ka=%d",
+                        is11,   iska,   iscl,   isps,   keepalive);
+       k_hashtable_set(evt_head, "Connection:", 
+                                 keepalive? "Keep-Alive": "close");
+}
+
+void fix_cache_control(k_hashtable* ent_head)
+{
+       char* cachec=k_hashtable_get(    ent_head, "Cache-Control:");
+       char* pragma=k_hashtable_extract(ent_head, "Pragma:");
+       if(!cachec && pragma && strstr(pragma, "no-cache")){
+               k_hashtable_set(         ent_head, "Cache-Control:","no-cache");
+       }
+}
+
+void fix_uri(k_hashtable* ent_head)
+{
+       char* uri=k_hashtable_get(ent_head, "URI:");
+       if(!uri) return;
+       char* nihostname=ni_hostname();
+       int l=strlen(nihostname);
+       if(strncmp(uri, nihostname, l)) return;
+       snprintf(tmpbuf, TMPBUFSIZE, ".%s", uri+l);
+       k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
+}
+
+void fix_subscribe(k_hashtable* evt_head, k_hashtable* ent_head)
+{
+       char* host=k_hashtable_extract(evt_head, "Host:");
+       char* file=k_hashtable_extract(evt_head, "File:");
+       if(host){
+               k_string_url_decode(host);
+               int localhostdns=!strcmp( host, "localhost") ||
+                                !strncmp(host, "localhost:", 10);
+               int localhostni=!strcmp(host, ni_hostname());
+               char* lastdot=strrchr(host, '.');
+               int dotdotnumber=lastdot && atoi(lastdot+1) >0;
+               if(localhostdns || localhostni || dotdotnumber){
+                       host=".";
+               }
+       }
+       else{
+               host=".";
+       }
+       if(file){
+               k_string_url_decode(file);
+               snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file);
+               k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf);
+               k_hashtable_set(    ent_head, "Sub-Type:", "Original");
+       }
+}
+
+void init_headers(void)
+{
+       entity_headers  =k_hashtable_new("Entity Headers", 1);
+
+       k_hashtable_set(entity_headers, "URI:", (void*)1);
+       k_hashtable_set(entity_headers, "From:", (void*)1);
+       k_hashtable_set(entity_headers, "To:", (void*)1);
+       k_hashtable_set(entity_headers, "Via:", (void*)1);
+       k_hashtable_set(entity_headers, "Sub-To:", (void*)1);
+       k_hashtable_set(entity_headers, "Sub-Type:", (void*)1);
+       k_hashtable_set(entity_headers, "Method:", (void*)1);
+       k_hashtable_set(entity_headers, "Status:", (void*)1);
+       k_hashtable_set(entity_headers, "Status-Text:", (void*)1);
+       k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1);
+       k_hashtable_set(entity_headers, "CUX:", (void*)1);
+
+       k_hashtable_set(entity_headers, "Range:", (void*)1);
+       k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1);
+       k_hashtable_set(entity_headers, "If-None-Match:", (void*)1);
+       k_hashtable_set(entity_headers, "Cache-Control:", (void*)1);
+       k_hashtable_set(entity_headers, "Pragma:", (void*)1);
+
+       k_hashtable_set(entity_headers, "Content-Length:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-Type:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-Location:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-MD5:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-Language:", (void*)1);
+       k_hashtable_set(entity_headers, "Content-Range:", (void*)1);
+       k_hashtable_set(entity_headers, "Last-Modified:", (void*)1);
+       k_hashtable_set(entity_headers, "ETag:", (void*)1);
+       k_hashtable_set(entity_headers, "Expires:", (void*)1);
+
+       k_hashtable_set(entity_headers, "Allow:", (void*)1);
+}
+
+void drop_entity_headers(k_hashtable* ent_head)
+{
+       k_hashtable_remove(ent_head, "Content-Length:");
+       k_hashtable_remove(ent_head, "Content-Range:");
+       k_hashtable_remove(ent_head, "Content-Type:");
+       k_hashtable_remove(ent_head, "Content-Encoding:");
+       k_hashtable_remove(ent_head, "Content-Location:");
+       k_hashtable_remove(ent_head, "Last-Modified:");
+#ifdef DO_THESE_ONES_TOO
+       k_hashtable_remove(ent_head, "Allow:");
+       k_hashtable_remove(ent_head, "Content-Language:");
+       k_hashtable_remove(ent_head, "Content-MD5:");
+       k_hashtable_remove(ent_head, "Expires:");
+#endif
+}
+
+void fill_headers(k_hashtable* ent_head,
+                  char*  status,
+                  char*  statustext,
+                  char*  uri,
+                  time_t modifitime,
+                  int    datalength,
+                  char*  mimetype,
+                  char*  encoding,
+                  int    nocache)
+{
+       if(status){
+               k_hashtable_put_dup(ent_head, "Status:",      status);
+               k_hashtable_put_dup(ent_head, "Status-Text:", statustext);
+       }
+       if(uri){
+               k_hashtable_put_dup(ent_head, "URI:", uri);
+       }
+       if(modifitime>=0){
+               snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime));
+               k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf);
+       }
+       if(datalength>=0){
+               snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength);
+               k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf);
+       }
+       if(mimetype){
+               k_hashtable_put_dup(ent_head, "Content-Type:",   mimetype);
+       }
+       if(encoding){
+               k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding);
+       }
+       if(nocache==1){
+               k_hashtable_put_dup(ent_head, "Cache-Control:",
+                                             "no-cache,no-store");
+       }
+       else
+       if(nocache==0){
+               long maxage=31449600;
+               snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage);
+               char* maxages=k_time_to_rfc_relative(maxage);
+               k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf);
+               k_hashtable_put_dup(ent_head, "Expires:", maxages);
+       }
+       else
+       if(nocache== -1){
+               k_hashtable_remove(ent_head, "Cache-Control:");
+               k_hashtable_remove(ent_head, "Expires:");
+       }
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
diff --git a/src/on/notification.c b/src/on/notification.c
new file mode 100644 (file)
index 0000000..970b1cb
--- /dev/null
@@ -0,0 +1,824 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#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);
+       }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+
+
+
index e8e2854..e32c1b5 100644 (file)
@@ -285,7 +285,7 @@ void dir_read(char*  basedir,
                }
                else{
                        is_np=1;
-                       k_ciux="np";
+                       k_ciux="op";
                }
                k_free(data);
        }
@@ -294,8 +294,8 @@ void dir_read(char*  basedir,
 
        k_log_out("========================================");
 
-       load_module("ni", 0);
-       load_module("np", 0);
+       load_module("on", 0);
+       load_module("op", 0);
        if(!is_np) load_module(k_ciux, 1);
 
        k_log_out("========================================");