f0ccc5f2b91a646b77f56dc3064a24cd3aaa4bf8
[cilux] / src / ni / ni.c
1
2 /* -}{----------------------------------------------------------------------- */
3
4 #include <kernelapi.h>
5 #undef  PUBLIC
6 #define PUBLIC EXPORT
7 #include <ni.h>
8
9 /* -}{---- ------------------------------------------------------------------ */
10
11 #define TMPBUFSIZE  4096
12 static char         tmpbuf[TMPBUFSIZE];
13 static char*        hostname;
14 static k_hashtable* resources;
15
16 /* -}{---- ------------------------------------------------------------------ */
17
18 typedef struct ni_driver{
19         char*                name;
20         ni_handles_resource handles_resource;
21         ni_sync_resource    sync_resource;
22 } ni_driver;
23
24 /* -}{---- From headers.c --------------------------------------------------- */
25
26 extern void  init_headers(void);
27 extern void  drop_entity_headers(k_hashtable* ent_head);
28 extern void  fill_headers(k_hashtable* ent_head,
29                           char*  status,
30                           char*  statustext,
31                           char*  uri,
32                           time_t modifitime,
33                           int    datalength,
34                           char*  mimetype,
35                           char*  encoding,
36                           int    nocache);
37
38 /* -}{---- ------------------------------------------------------------------ */
39
40 static void          incoming_request(ni_event* evq);
41 static ni_resource* ensure_res(char* pub);
42 static void          ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub);
43 static void          ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub);
44 static k_hashtable* get_this(k_hashtable*, char*, k_hashtable*);
45 static k_hashtable* get_using(k_hashtable* curr, char* tag, char* val);
46 static void          post_to_driver(char* pub, ni_event* evq);
47 static void          incoming_resource(ni_event* evt);
48 static void    test_pub_tos(ni_resource* res, ni_event* evt, int entityok);
49 static int     satisfiable(k_hashtable*, ni_resource*, ni_event*, int);
50 static void    update_pubcache(int, k_hashtable**, k_hashtable*, k_hashtable*);
51 static int     sub_less(k_hashtable* sub1, k_hashtable* sub2);
52 static void    fix_via_subs(k_hashtable* evteh, k_hashtable* reseh);
53 static int     sub_ok(k_hashtable* sub);
54 static int     range_ok(char* range, char* conrange);
55 static void    merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh);
56 static void    merge_entity_range(ni_resource* res, ni_event* evt);
57 static void    respond(   k_hashtable* sub, ni_resource* res, ni_event* evt);
58 static void    respond_ok(k_hashtable* sub, ni_event* evv);
59 static void    respond_nf(k_hashtable* sub, ni_event* evv);
60 static void*   entity_to_octets(k_hashtable* ent_head, void* entity);
61 static char*       handled_by(char* pub);
62 static void        call_sync_resource(ni_resource* res);
63 static ni_driver* ni_driver_new(char*                name,
64                                   ni_handles_resource handles_resource,
65                                   ni_sync_resource    sync_resource);
66
67 /* -}{---- ------------------------------------------------------------------ */
68
69 EXPORT int ni_module_loaded(void)
70 {
71         resources=k_hashtable_new("Resources", 0);
72
73         init_headers();
74
75         k_log_out("NI initialised");
76         return 1;
77 }
78
79 EXPORT void ni_module_tick(void)
80 {
81 }
82
83 EXPORT int ni_module_event(void* data)
84 {
85         ni_event* evt=data;
86
87         if(!k_hashtable_get(evt->ent_head, "Status:")){
88
89                 incoming_request(evt);
90         }
91         else{
92                 incoming_resource(evt);
93         }
94         return 1;
95 }
96
97 /* -}{---- ------------------------------------------------------------------ */
98
99 void incoming_request(ni_event* evq)
100 {
101         int L=1;
102         if(L) ni_event_show(evq, "NI got request event");
103
104         k_hashtable* sub=evq->ent_head;
105         char* uri  =k_hashtable_get(sub, "URI:");
106         char* pub  =k_hashtable_get(sub, "Sub-To:"); if(!pub) return;
107         int   styor=k_hashtable_isi(sub, "Sub-Type:", "Original");
108         char* via  =k_hashtable_get(sub, "Via:");
109         char* from =k_hashtable_get(sub, "From:");
110         if(L) k_log_out("------------------ %s", pub);
111
112         int nocache=k_hashtable_isi(sub, "Cache-Control:", "no-cache");
113         if(nocache){
114                 k_hashtable_remove( sub, "Cache-Control:");
115                 k_hashtable_set(    sub, "If-Modified-Since:", "0");
116         }
117
118         if(!from){
119                 ni_resource* ses=k_hashtable_get(resources, uri);
120                 if(ses) ensure_sub_entry(ses->ent_head, sub);
121                 if(ses) if(L) ni_resource_show(ses, "Subscribing Resource:");
122                 if(styor && via){
123                         post_to_driver(pub, evq);
124                         return;
125                 }
126         }
127
128         ni_resource* res=ensure_res(pub);
129         if(L) ni_resource_show(res, "Publishing Resource:");
130
131         k_hashtable* pubcache=0;
132         int sat=satisfiable(sub, res, 0, 0);
133         update_pubcache(sat, &pubcache, res->ent_head, sub);
134         if(sat){
135                 if(L) k_log_out("Memory cache hit for %s", pub);
136                 respond(k_hashtable_dup(sub), res, 0);
137                 ni_event_delete(evq);
138         }
139         else{
140                 ensure_pub_entry(res->ent_head, sub);
141                 if(L) ni_resource_show(res, "Pending Resource:");
142                 if(pubcache){
143                         evq->ent_head=pubcache;
144                         post_to_driver(pub, evq);
145                         k_hashtable_delete(sub);
146                 }
147                 else{
148                         if(L) k_log_out("In-progress Pub-Cache sufficient");
149                         ni_event_delete(evq);
150                 }
151         }
152 }
153
154 ni_resource* ensure_res(char* pub)
155 {
156         ni_resource* res=k_hashtable_get(resources, pub);
157         if(!res){
158                 res=ni_resource_new(pub, k_hashtable_new("resHeaders", 1), 0);
159                 k_hashtable_set(resources, pub, res);
160         }
161         return res;
162 }
163
164 void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub)
165 {
166         char* tag="Sub-To:";
167         k_hashtable* sup=get_this(ent_head, tag, sub);
168         if(!sup){
169                 k_hashtable* sup=k_hashtable_dup(sub);
170                 char* uri=k_hashtable_extract(sup, "Sub-To:");
171                 k_hashtable_put(              sup, "URI:", uri);
172                 k_hashtable_remove(           sup, "Sub-Type:");
173                 k_hashtable_sub(ent_head, tag, sup);
174         }
175         else{
176                 k_hashtable_remove(sup, "Range:");
177                 k_hashtable_remove(sup, "Content-Range:");
178                 k_hashtable_remove(sup, "Status:");
179                 k_hashtable_remove(sup, "Status-Cache:");
180                 char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
181                 char* via=k_strdup(k_hashtable_get(sub, "Via:"));
182                 char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
183                 char* rng=k_strdup(k_hashtable_get(sub, "Range:"));
184                 if(mth) k_hashtable_put(sup, "Method:",            mth);
185                 if(via) k_hashtable_put(sup, "Via:",               via);
186                 if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
187                 if(rng) k_hashtable_put(sup, "Range:",             rng);
188         }
189 }
190
191 void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub)
192 {
193         char* tag="Pub-To:";
194         k_hashtable* sup=get_this(ent_head, tag, sub);
195         if(!sup){
196                 k_hashtable* sup=k_hashtable_dup(sub);
197                 k_hashtable_remove(sup, "Sub-To:");
198                 k_hashtable_remove(sup, "Sub-Type:");
199                 k_hashtable_sub(ent_head, tag, sup);
200         }
201         else {
202                 k_hashtable_remove(sup, "Method:");
203                 k_hashtable_remove(sup, "If-Modified-Since:");
204                 k_hashtable_remove(sup, "Cache-Control:");
205                 k_hashtable_remove(sup, "Update:");
206                 char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
207                 char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
208                 char* ccn=k_strdup(k_hashtable_get(sub, "Cache-Control:"));
209                 char* upd=k_strdup(k_hashtable_get(sub, "Update:"));
210                 if(mth) k_hashtable_put(sup, "Method:",            mth);
211                 if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
212                 if(ccn) k_hashtable_put(sup, "Cache-Control:",     ccn);
213                 if(upd) k_hashtable_put(sup, "Update:",            upd);
214         }
215 }
216
217 k_hashtable* get_this(k_hashtable* ent_head, char* pubsub, k_hashtable* try)
218 {
219         k_hashtable* curr=k_hashtable_get(ent_head, pubsub);
220         if(!curr) return 0;
221
222         char* tag;
223         char* val;
224
225         tag="From:";
226         val=k_hashtable_get(try, tag);
227         if(val) return get_using(curr, tag, val);
228
229         tag="URI:";
230         val=k_hashtable_get(try, tag);
231         if(val) return get_using(curr, tag, val);
232
233         return 0;
234 }
235
236 k_hashtable* get_using(k_hashtable* curr, char* tag, char* val)
237 {
238         k_hashtable* c;
239         for(c=curr; c; c=c->next) if(k_hashtable_is(c, tag, val)) return c;
240         return c;
241 }
242
243 /* -}{---- ------------------------------------------------------------------ */
244
245 void incoming_resource(ni_event* evt)
246 {
247         int L=0;
248         if(L) ni_event_show(evt, "ni got resource incoming event");
249
250         ni_resource* res=k_hashtable_get(resources, evt->uri);
251         int fullconst=res && k_hashtable_is(res->ent_head, "Status:", "200") &&
252                              k_hashtable_is(res->ent_head, "CUX:",    "C");
253
254         if(fullconst){
255                 k_log_err("Resource is complete and Constant");
256                 ni_event_delete(evt);
257                 return;
258         }
259         if(!res) res=ensure_res(evt->uri);
260
261         k_hashtable* reseh=res->ent_head;
262         k_hashtable* evteh=evt->ent_head;
263         int okfull  =k_hashtable_is(evteh, "Status:", "200");
264         int partial =k_hashtable_is(evteh, "Status:", "206");
265         int headonly=k_hashtable_is(evteh, "Status:", "260");/*
266         int updated =k_hashtable_is(evteh, "Status:", "266");*/
267         int notmod  =k_hashtable_is(evteh, "Status:", "304");
268         int notfound=k_hashtable_is(evteh, "Status:", "404");
269
270         int entityok= (okfull || partial || notmod);
271         int entityev=!(headonly || notmod || notfound);
272         int entityin=!!evt->entity;
273         int entityon=!!res->entity;
274
275         if(!entityev){
276         }
277         if(okfull || !entityon){
278                 k_hashtable_merge(reseh, evteh);
279                 if(okfull) k_hashtable_remove(reseh, "Content-Range:");
280         }
281         else{
282                 merge_non_entity_headers(reseh, evteh);
283         }
284
285         fix_via_subs(evteh, reseh);
286
287         if(entityin){
288                 if(okfull || (partial && !entityon)){
289                         if(res->entity!=evt->entity){
290                                 if(!k_hashtable_is(reseh, "CUX:", "C")){
291                                         k_free(res->entity);
292                                 }
293                                 res->entity=evt->entity;
294                         }
295                 }
296                 else
297                 if(partial && entityon){
298                         merge_entity_range(res, evt);
299                 }
300         }
301
302         if(L) ni_resource_show(res, "updated resource - sync and try pubs:");
303
304         call_sync_resource(res);
305
306         test_pub_tos(res, evt, entityok);
307
308         evt->entity=0;
309         ni_event_delete(evt);
310
311         if(L) ni_resource_show(res, "resource after ni:");
312 }
313
314 void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh)
315 {
316         char* from=k_hashtable_get(evteh, "From:");
317         if(!from) return;
318         k_hashtable* subs=k_hashtable_get(reseh, "Sub-To:");
319         k_hashtable* sub;
320         for(sub=subs; sub; sub=sub->next){
321                 if(!k_hashtable_is(sub, "Via:", from)) continue;
322                 int   st=k_hashtable_get_int(evteh, "Status:");
323                 char* cr=k_hashtable_get_dup(evteh, "Content-Range:");
324                 if(st!=304) k_hashtable_put_int(sub, "Status:", st);
325                 if(st==200) k_hashtable_remove( sub, "Content-Range:");
326                 else
327                 if(cr)          k_hashtable_put(sub, "Content-Range:", cr);
328                 if(sub_ok(sub)) k_hashtable_set(sub, "Status-Cache:", "OK");
329         }
330 }
331
332 void test_pub_tos(ni_resource* res, ni_event* evt, int entityok)
333 {
334         k_hashtable* keeps=0;
335         k_hashtable* sub=k_hashtable_extract(res->ent_head, "Pub-To:");
336         while(sub){
337                 k_hashtable* subnext=sub->next;
338                 sub->next=0;
339                 int keep=1;
340                 int sat=satisfiable(sub, res, evt, entityok);
341                 update_pubcache(sat, 0, res->ent_head, sub);
342                 if(sat){
343                         respond(k_hashtable_dup(sub), res, evt);
344                         if(!k_hashtable_get(sub, "Update:")) keep=0;
345                 }
346                 if(keep){
347                         sub->next=keeps;
348                         keeps=sub;
349                 }
350                 else{
351                         k_hashtable_delete(sub);
352                 }
353                 sub=subnext;
354         }
355         sub=keeps;
356         while(sub){
357                 k_hashtable* subnext=sub->next;
358                 k_hashtable_sub(res->ent_head, "Pub-To:", sub);
359                 sub=subnext;
360         }
361 }
362
363 int satisfiable(k_hashtable*  sub,
364                 ni_resource* res,
365                 ni_event*    evt,
366                 int           entityok)
367 {
368         int L=0;
369         int   get  =k_hashtable_is( sub, "Method:", "GET");
370         int   head =k_hashtable_is( sub, "Method:", "HEAD");
371         int   dosub=k_hashtable_is( sub, "Method:", "SUB");
372         int   unsub=k_hashtable_is( sub, "Method:", "UNSUB");
373         int   full=!k_hashtable_isi(sub, "Cache-Control:", "no-full");
374         int   updt =k_hashtable_isi(sub, "Update:", "changes");
375         char* ims  =k_hashtable_get(sub, "If-Modified-Since:");
376         char* range=k_hashtable_get(sub, "Range:");
377
378         int getsub  =get || dosub;
379         int getrange=getsub && range;
380
381         k_hashtable* reseh=res->ent_head;
382         int   gotall=    k_hashtable_is( reseh, "Status:", "200");
383         int   gotrange=  k_hashtable_is( reseh, "Status:", "206");
384         int   gothead=   k_hashtable_is( reseh, "Status:", "260");
385         int   gotupdated=evt && 
386                          k_hashtable_is(evt->ent_head, "Status:", "266");
387         int   notfound=  k_hashtable_is( reseh, "Status:", "404");
388         int   constant=  k_hashtable_is( reseh, "CUX:",    "C"  );
389         char* conrange=  k_hashtable_get(reseh, "Content-Range:");
390
391         if(unsub)    return 0;
392         if(notfound) return 1;
393
394         int gotany=(gothead || gotrange || gotall);
395         int snapok=(constant || !ims || entityok);
396
397         int sat=
398            (full && 
399             ((getsub   && gotall                                && snapok) ||
400              (getrange && gotrange && range_ok(range, conrange) && snapok) ||
401              (head     && gotany                                         )   ))
402              ||
403            (updt &&
404             ((dosub    && gotupdated)));
405
406         if(L) k_log_out("satisfiable %d", sat);
407         return sat;
408 }
409
410 void update_pubcache(int           sat,
411                      k_hashtable** pubcachep,
412                      k_hashtable*  reseh,
413                      k_hashtable*  sub)
414 {
415         if(!sat){ if(pubcachep){
416                 k_hashtable* pubcache;
417                 pubcache=k_hashtable_get(reseh, "Pub-Cache:");
418                 if(!pubcache || sub_less(pubcache, sub)){
419                         if(!pubcache){
420                                 pubcache=k_hashtable_dup(sub);
421                                 k_hashtable_sub(reseh, "Pub-Cache:", pubcache);
422                         }
423                         else{
424                                 k_hashtable_merge(pubcache, sub);
425                         }
426                         k_hashtable_remove(pubcache, "URI:");
427                         k_hashtable_remove(pubcache, "Sub-Type:");
428                         *pubcachep=k_hashtable_dup(pubcache);
429                         k_hashtable_set(*pubcachep, "Sub-Type:", "Cache");
430                 }
431         }}
432         else{ if(!pubcachep){
433                 k_hashtable* pubcache;
434                 pubcache=k_hashtable_get(reseh, "Pub-Cache:");
435                 if(!sub_less(sub, pubcache)){
436                         k_hashtable_remove(pubcache, "Method:");
437                         k_hashtable_remove(pubcache, "If-Modified-Since:");
438                 }
439         }}
440 }
441
442 int sub_ok(k_hashtable* sub)
443 {
444         char* gotresp =k_hashtable_get(sub, "Status:");
445         if(!gotresp) return 0;
446         int   notfound=k_hashtable_is( sub, "Status:", "404");
447         if(notfound) return 0;
448         int   gotall  =k_hashtable_is( sub, "Status:", "200");
449         int   gotrange=k_hashtable_is( sub, "Status:", "206");
450         int   gothead= k_hashtable_is( sub, "Status:", "260");
451         int   doget   =k_hashtable_is( sub, "Method:", "GET");
452         int   dohead  =k_hashtable_is( sub, "Method:", "HEAD");
453         int   dosub   =k_hashtable_is( sub, "Method:", "SUB");
454         char* range   =k_hashtable_get(sub, "Range:");
455         char* conrange=k_hashtable_get(sub, "Content-Range:");
456
457         int dogetsub=doget || dosub;
458         int dogetrange=dogetsub && range;
459         int gotany  =(gothead || gotrange || gotall);
460
461         return (dogetsub   &&  gotall                               ) ||
462                (dogetrange &&  gotrange && range_ok(range, conrange)) ||
463                (dohead     &&  gotany                               );
464 }
465
466 int sub_less(k_hashtable* sub1, k_hashtable* sub2)
467 {
468         int L=0;
469         if(L) k_log_out("sub_less sub1:");
470         if(L) k_hashtable_show_chars(sub1);
471         if(L) k_log_out("sub_less sub2:");
472         if(L) k_hashtable_show_chars(sub2);
473         char* mth1 =k_hashtable_get(sub1, "Method:");
474         int   head1=k_hashtable_is( sub1, "Method:", "HEAD");
475         int   get2 =k_hashtable_is( sub2, "Method:", "GET");
476         char* ims1 =k_hashtable_get(sub1, "If-Modified-Since:");
477         char* ims2 =k_hashtable_get(sub2, "If-Modified-Since:");
478         int   full=!k_hashtable_isi(sub2, "Cache-Control:", "no-full");
479         return full && ((!mth1) || (head1 && get2) || (!ims1 && ims2));
480 }
481
482 int range_ok(char* range, char* conrange)
483 {
484         k_log_out("range_ok not implemented: %s vs %s", range, conrange);
485         return 0;
486 }
487
488 void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh)
489 {
490 }
491
492 void merge_entity_range(ni_resource* res, ni_event* evt)
493 {
494         k_log_out("merge_entity_range not implemented yet");
495 }
496
497 /* -}{---- ------------------------------------------------------------------ */
498
499 void respond(k_hashtable* sub, ni_resource* res, ni_event* evt)
500 {
501         int updated=evt && k_hashtable_is(evt->ent_head, "Status:", "266");
502         ni_event* evv=updated? ni_event_dup(evt): 
503                                 ni_res_to_evt(res);
504         int L=0;
505         if(L) ni_event_show(evv, "respond");
506
507         k_hashtable_remove(evv->ent_head, "Permit:");
508         k_hashtable_remove(evv->ent_head, "Sub-To:");
509         k_hashtable_remove(evv->ent_head, "Pub-To:");
510         k_hashtable_remove(evv->ent_head, "Pub-Cache:");
511         k_hashtable_sub(   evv->ent_head, "Pub-To:", sub);
512
513         int nf;
514         nf=k_hashtable_is( evv->ent_head, "Status:", "404");
515         if(!nf) respond_ok(sub, evv);
516         else    respond_nf(sub, evv);
517 }
518
519 void respond_ok(k_hashtable* sub, ni_event* evv)
520 {
521         char* status=0;
522         char* statustext=0;
523         int   datalength= -1;
524         int   nocache=0;
525         k_hashtable* ent_head=evv->ent_head;
526
527         time_t modifitime=k_hashtable_get_int(ent_head, "Last-Modified-Epoch:");
528         char*  modistring=k_hashtable_get(    ent_head, "Last-Modified:");
529         if(!modifitime){
530                 modifitime=k_time_from_rfc(modistring);
531         }
532         char*  imss=k_hashtable_get(sub, "If-Modified-Since:");
533         time_t imst=k_time_from_rfc(imss);
534
535         if(modifitime== -1 || imst== -1 || modifitime > imst){
536                 if(k_hashtable_is(sub, "Method:", "HEAD")){
537                         evv->entity=0;
538                 }
539                 if(!k_hashtable_is(ent_head, "CUX:", "C")){
540                         evv->entity=entity_to_octets(ent_head, evv->entity);
541                         nocache=1;
542                 }
543         }
544         else{
545                 status="304";
546                 statustext="Not Modified";
547                 modifitime= -1;
548                 nocache= -1;
549                 evv->entity=0;
550                 drop_entity_headers(ent_head);
551         }
552
553         fill_headers(ent_head, status, statustext, 0,
554                      modistring? -1: modifitime,
555                      datalength, 0, 0, nocache);
556
557         char*  pub =k_hashtable_get(sub, "URI:");
558         int L=0;
559         if(L) ni_event_show(evv, "respond_ok");
560         post_to_driver(pub, evv);
561 }
562
563 void respond_nf(k_hashtable* sub, ni_event* evv)
564 {
565         fill_headers(evv->ent_head, "404", "File Not Found", 0, -1, 0, 0, 0, 1);
566         char*  pub =k_hashtable_get(sub, "URI:");
567         post_to_driver(pub, evv);
568 }
569
570 void post_to_driver(char* pub, ni_event* evq)
571 {
572         char* driver=handled_by(pub);
573         if(0) k_log_out("Passing %s on to %s", pub, driver);
574         if(0) ni_event_show(evq, "Post to Driver:");
575         k_event_post(driver, evq);
576 }
577
578 void* entity_to_octets(k_hashtable* ent_head, void* entity)
579 {
580         if(!entity) return 0;
581         size_t size=k_hashtable_get_int(ent_head, "Content-Length:");
582         return k_memdup(entity, size);
583 }
584
585 /* -}{---- ------------------------------------------------------------------ */
586
587 EXPORT char* ni_hostname()
588 {
589         return hostname? hostname: "not set";
590 }
591
592 EXPORT void ni_hostname_set(char* name)
593 {
594         k_free(hostname);
595         hostname=k_strdup(name);
596 }
597
598 /* -}{---- ------------------------------------------------------------------ */
599
600 static ni_driver* npdriver;
601 static ni_driver* moddriver;
602
603 char* handled_by(char* pub)
604 {
605         if(moddriver->handles_resource(pub)) return moddriver->name;
606         return "np";
607 }
608
609 void call_sync_resource(ni_resource* res)
610 {
611         if(moddriver->handles_resource(res->uri)) moddriver->sync_resource(res);
612         else                                      npdriver->sync_resource(res);
613 }
614
615 ni_driver* ni_driver_new(char*                name, 
616                            ni_handles_resource handles_resource,
617                            ni_sync_resource    sync_resource)
618 {
619         ni_driver* driver=k_malloc(sizeof(ni_driver));
620         driver->name            =name;
621         driver->handles_resource=handles_resource;
622         driver->sync_resource   =sync_resource;
623         return driver;
624 }
625
626 EXPORT void ni_register_driver(char*                name,
627                                 ni_handles_resource handles_resource,
628                                 ni_sync_resource    sync_resource)
629 {
630         ni_driver* d=ni_driver_new(name, handles_resource, sync_resource);
631         if(!strcmp(name, "np")) npdriver=d;
632         else                     moddriver=d;
633 }
634
635 /* -}{---- ------------------------------------------------------------------ */
636
637 EXPORT ni_resource* ni_resource_new(char*        uri,
638                                       k_hashtable* ent_head,
639                                       char*        entity)
640 {
641         char* urih=k_hashtable_get(ent_head, "URI:");
642         if(urih) uri=urih;
643         else
644         if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
645
646         ni_resource* res=k_malloc(sizeof(ni_resource));
647         res->uri     =(uri? k_strdup(uri): 0);
648         res->ent_head=ent_head;
649         res->entity  =entity;
650         return res;
651 }
652
653 EXPORT ni_resource* ni_resource_dup(ni_resource* res)
654 {
655         ni_resource* rep=k_malloc(sizeof(ni_resource));
656         rep->uri     =k_strdup(       res->uri);
657         rep->ent_head=k_hashtable_dup(res->ent_head);
658         rep->entity  =                res->entity;
659         return rep;
660 }
661
662 EXPORT void ni_resource_delete(ni_resource* res)
663 {
664         if(!res) return;
665         if(res->entity && res->ent_head){
666                 int constant=k_hashtable_is(res->ent_head, "CUX:", "C");
667                 if(!constant) k_free(res->entity);
668         }
669         k_hashtable_delete(res->ent_head);
670         k_free(            res->uri);
671         k_free(            res);
672 }
673
674 static char* excto[]={ "Permit:", "Sub-To:", "Pub-To:", 0 };
675 static char* perto[]={ "Permit:", 0 };
676 static char* subto[]={ "Sub-To:",    0 };
677 static char* pubto[]={ "Pub-To:",    0 };
678
679 EXPORT void ni_resource_show(ni_resource* res, char* text)
680 {
681         if(!res){
682                 k_log_out("\n---%s--------\n------------\n\n----------",
683                                 text);
684         }
685         else{
686                 char*  b=tmpbuf;
687                 size_t s=TMPBUFSIZE;
688                 size_t l=0;
689                 l+=k_hashtable_snprintf_x(res->ent_head, b+l, s-l, excto);
690                 l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, perto);
691                 l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, subto);
692                 l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, pubto);
693                 k_log_out("\n---%s----%s--\n%s----------\n%p\n----------", 
694                                 text, res->uri, tmpbuf, res->entity);
695         }
696 }
697
698 /* -}{---- ------------------------------------------------------------------ */
699
700 EXPORT ni_resource* ni_resource_get(char* uri)
701 {
702         return k_hashtable_get(resources, uri);
703 }
704
705 /* -}{---- ------------------------------------------------------------------ */
706
707 EXPORT ni_event* ni_res_to_evt(ni_resource* res)
708 {
709         ni_event* evp=k_malloc(sizeof(ni_event));
710         evp->uri     =k_strdup(       res->uri);
711         evp->evt_head=k_hashtable_new("vHeaders/ni_res_to_evt", 1);
712         evp->ent_head=k_hashtable_dup(res->ent_head);
713         evp->entity  =                res->entity;
714         return evp;
715 }
716
717 /* -}{---- ------------------------------------------------------------------ */
718
719 EXPORT ni_event* ni_event_new(char*        uri,
720                                 k_hashtable* evt_head,
721                                 k_hashtable* ent_head,
722                                 char*        entity)
723 {
724         char* urih=k_hashtable_get(ent_head, "URI:");
725         if(urih) uri=urih;
726         else
727         if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
728
729         ni_event* evt=k_malloc(sizeof(ni_event));
730         evt->uri     =(uri? k_strdup(uri): 0);
731         evt->evt_head=evt_head;
732         evt->ent_head=ent_head;
733         evt->entity  =entity;
734         return evt;
735 }
736
737 EXPORT ni_event* ni_event_dup(ni_event* evt)
738 {
739         ni_event* evp=k_malloc(sizeof(ni_event));
740         evp->uri     =k_strdup(       evt->uri);
741         evp->evt_head=k_hashtable_dup(evt->evt_head);
742         evp->ent_head=k_hashtable_dup(evt->ent_head);
743         evp->entity  =                evt->entity;
744         return evp;
745 }
746
747 EXPORT void ni_event_delete(ni_event* evt)
748 {
749         if(!evt) return;
750         if(evt->entity && evt->ent_head){
751                 int constant=k_hashtable_is(evt->ent_head, "CUX:", "C");
752                 if(!constant) k_free(evt->entity);
753         }
754         k_hashtable_delete(evt->evt_head);
755         k_hashtable_delete(evt->ent_head);
756         k_free(            evt->uri);
757         k_free(            evt);
758 }
759
760 EXPORT void ni_event_show(ni_event* evt, char* text)
761 {
762         if(!evt){
763                 k_log_out("\n---%s--------\n------------\n\n----------",
764                                 text);
765         }
766         else{
767                 char* buf=tmpbuf;
768                 int   siz=TMPBUFSIZE;
769                 int n=k_hashtable_snprintf(evt->evt_head, buf,   siz)+1;
770                 ;     k_hashtable_snprintf(evt->ent_head, buf+n, siz-n);
771                 k_log_out("\n---%s----%s--\n"
772                           "%s----------\n"
773                           "%s----------\n"
774                           "%p\n----------", 
775                                 text, evt->uri, buf, buf+n, evt->entity);
776         }
777 }
778
779 /* -}{----------------------------------------------------------------------- */
780
781
782
783