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