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