Change forms of get_vhost functions.. get_vhost_otherinfo returns
[metaproxy-moved-to-github.git] / src / util.cpp
1 /* $Id: util.cpp,v 1.19 2006-08-30 12:27:34 adam Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8
9 #include <yaz/odr.h>
10 #include <yaz/pquery.h>
11 #include <yaz/otherinfo.h>
12 #include <yaz/querytowrbuf.h> // for yaz_query_to_wrbuf()
13 #include "util.hpp"
14
15 //#include <iostream>
16
17 namespace mp = metaproxy_1;
18
19 // Doxygen doesn't like mp::util, so we use this instead
20 namespace mp_util = metaproxy_1::util;
21
22 int mp_util::memcmp2(const void *buf1, int len1,
23                      const void *buf2, int len2)
24 {
25     int d = len1 - len2;
26
27     // compare buffer (common length)
28     int c = memcmp(buf1, buf2, d > 0 ? len2 : len1);
29     if (c > 0)
30         return 1;
31     else if (c < 0)
32         return -1;
33     
34     // compare (remaining bytes)
35     if (d > 0)
36         return 1;
37     else if (d < 0)
38         return -1;
39     return 0;
40 }
41
42
43 std::string mp_util::database_name_normalize(const std::string &s)
44 {
45     std::string r = s;
46     size_t i;
47     for (i = 0; i < r.length(); i++)
48     {
49         int ch = r[i];
50         if (ch >= 'A' && ch <= 'Z')
51             r[i] = ch + 'a' - 'A';
52     }
53     return r;
54
55 }
56
57 void mp_util::piggyback(int smallSetUpperBound,
58                                   int largeSetLowerBound,
59                                   int mediumSetPresentNumber,
60                                   int result_set_size,
61                                   int &number_to_present)
62 {
63     // deal with piggyback
64
65     if (result_set_size < smallSetUpperBound)
66     {
67         // small set . Return all records in set
68         number_to_present = result_set_size;
69     }
70     else if (result_set_size > largeSetLowerBound)
71     {
72         // large set . Return no records
73         number_to_present = 0;
74     }
75     else
76     {
77         // medium set . Return mediumSetPresentNumber records
78         number_to_present = mediumSetPresentNumber;
79         if (number_to_present > result_set_size)
80             number_to_present = result_set_size;
81     }
82 }
83
84
85 bool mp_util::pqf(ODR odr, Z_APDU *apdu, const std::string &q)
86 {
87     YAZ_PQF_Parser pqf_parser = yaz_pqf_create();
88     
89     Z_RPNQuery *rpn = yaz_pqf_parse(pqf_parser, odr, q.c_str());
90     if (!rpn)
91     {
92         yaz_pqf_destroy(pqf_parser);
93         return false;
94     }
95     yaz_pqf_destroy(pqf_parser);
96     Z_Query *query = (Z_Query *) odr_malloc(odr, sizeof(Z_Query));
97     query->which = Z_Query_type_1;
98     query->u.type_1 = rpn;
99     
100     apdu->u.searchRequest->query = query;
101     return true;
102 }
103
104
105 std::string mp_util::zQueryToString(Z_Query *query)
106 {
107     std::string query_str = "";
108
109     if (query && query->which == Z_Query_type_1){
110         Z_RPNQuery *rpn = query->u.type_1;
111         
112         if (rpn){
113             
114             // allocate wrbuf (strings in YAZ!)
115             WRBUF w = wrbuf_alloc();
116             
117             // put query in w
118             yaz_rpnquery_to_wrbuf(w, rpn);
119             
120             // from w to std::string
121             query_str = std::string(wrbuf_buf(w), wrbuf_len(w));
122             
123             // destroy wrbuf
124             wrbuf_free(w, 1);
125         }
126     }
127
128 #if 0
129     if (query && query->which == Z_Query_type_1){
130         
131         // allocate wrbuf (strings in YAZ!)
132         WRBUF w = wrbuf_alloc();
133         
134         // put query in w
135         yaz_query_to_wrbuf(w, query);
136         
137         // from w to std::string
138         query_str = std::string(wrbuf_buf(w), wrbuf_len(w));
139         
140         // destroy wrbuf
141         wrbuf_free(w, 1);
142     }    
143 #endif
144     return query_str;
145 }
146
147 void mp_util::get_default_diag(Z_DefaultDiagFormat *r,
148                                          int &error_code, std::string &addinfo)
149 {
150     error_code = *r->condition;
151     switch (r->which)
152     {
153     case Z_DefaultDiagFormat_v2Addinfo:
154         addinfo = std::string(r->u.v2Addinfo);
155         break;
156     case Z_DefaultDiagFormat_v3Addinfo:
157         addinfo = r->u.v3Addinfo;
158         break;
159     }
160 }
161
162 void mp_util::get_init_diagnostics(
163     Z_InitResponse *initrs, int &error_code, std::string &addinfo)
164 {
165     Z_External *uif = initrs->userInformationField;
166     
167     if (uif && uif->which == Z_External_userInfo1)
168     {
169         Z_OtherInformation *ui = uif->u.userInfo1;
170         int i;
171         for (i = 0; i < ui->num_elements; i++)
172         {
173             Z_OtherInformationUnit *unit = ui->list[i];
174             if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
175                 unit->information.externallyDefinedInfo &&
176                 unit->information.externallyDefinedInfo->which ==
177                 Z_External_diag1) 
178             {
179                 Z_DiagnosticFormat *diag = 
180                     unit->information.externallyDefinedInfo->u.diag1;
181
182                 if (diag->num > 0)
183                 {
184                     Z_DiagnosticFormat_s *ds = diag->elements[0];
185                     if (ds->which == Z_DiagnosticFormat_s_defaultDiagRec)
186                         mp::util::get_default_diag(ds->u.defaultDiagRec,
187                                                     error_code, addinfo);
188                 }
189             } 
190         }
191     }
192 }
193
194 int mp_util::get_or_remove_vhost_otherinfo(
195     Z_OtherInformation **otherInformation,
196     bool remove_flag,
197     std::list<std::string> &vhosts)
198 {
199     int cat;
200     for (cat = 1; ; cat++)
201     {
202         // check virtual host
203         const char *vhost =
204             yaz_oi_get_string_oidval(otherInformation,
205                                      VAL_PROXY, 
206                                      cat /* categoryValue */,
207                                      remove_flag /* delete flag */);
208         if (!vhost)
209             break;
210         vhosts.push_back(std::string(vhost));
211     }
212     --cat;
213     return cat;
214 }
215
216 void mp_util::get_vhost_otherinfo(
217     Z_OtherInformation *otherInformation,
218     std::list<std::string> &vhosts)
219 {
220     get_or_remove_vhost_otherinfo(&otherInformation, false, vhosts);
221 }
222
223 int mp_util::remove_vhost_otherinfo(
224     Z_OtherInformation **otherInformation,
225     std::list<std::string> &vhosts)
226 {
227     return get_or_remove_vhost_otherinfo(otherInformation, true, vhosts);
228 }
229
230 void mp_util::set_vhost_otherinfo(
231     Z_OtherInformation **otherInformation, ODR odr,
232     const std::list<std::string> &vhosts)
233 {
234     int cat;
235     std::list<std::string>::const_iterator it = vhosts.begin();
236     for (cat = 1; it != vhosts.end() ; cat++, it++)
237     {
238         yaz_oi_set_string_oidval(otherInformation, odr,
239                                  VAL_PROXY, cat, it->c_str());
240     }
241 }
242
243 void mp_util::split_zurl(std::string zurl, std::string &host,
244                                    std::list<std::string> &db)
245 {
246     const char *zurl_cstr = zurl.c_str();
247     const char *sep = strchr(zurl_cstr, '/');
248     
249     if (sep)
250     {
251         host = std::string(zurl_cstr, sep - zurl_cstr);
252
253         const char *cp1 = sep+1;
254         while(1)
255         {
256             const char *cp2 = strchr(cp1, '+');
257             if (cp2)
258                 db.push_back(std::string(cp1, cp2 - cp1));
259             else
260             {
261                 db.push_back(std::string(cp1));
262                 break;
263             }
264             cp1 = cp2+1;
265         }
266     }
267     else
268     {
269         host = zurl;
270     }
271 }
272
273 bool mp_util::set_databases_from_zurl(
274     ODR odr, std::string zurl,
275     int *db_num, char ***db_strings)
276 {
277     std::string host;
278     std::list<std::string> dblist;
279
280     split_zurl(zurl, host, dblist);
281    
282     if (dblist.size() == 0)
283         return false;
284     *db_num = dblist.size();
285     *db_strings = (char **) odr_malloc(odr, sizeof(char*) * (*db_num));
286
287     std::list<std::string>::const_iterator it = dblist.begin();
288     for (int i = 0; it != dblist.end(); it++, i++)
289         (*db_strings)[i] = odr_strdup(odr, it->c_str());
290     return true;
291 }
292
293 mp::odr::odr(int type)
294 {
295     m_odr = odr_createmem(type);
296 }
297
298 mp::odr::odr()
299 {
300     m_odr = odr_createmem(ODR_ENCODE);
301 }
302
303 mp::odr::~odr()
304 {
305     odr_destroy(m_odr);
306 }
307
308 mp::odr::operator ODR() const
309 {
310     return m_odr;
311 }
312
313 Z_APDU *mp::odr::create_close(const Z_APDU *in_apdu,
314                               int reason, const char *addinfo)
315 {
316     Z_APDU *apdu = create_APDU(Z_APDU_close, in_apdu);
317     
318     *apdu->u.close->closeReason = reason;
319     if (addinfo)
320         apdu->u.close->diagnosticInformation = odr_strdup(m_odr, addinfo);
321     return apdu;
322 }
323
324 Z_APDU *mp::odr::create_APDU(int type, const Z_APDU *in_apdu)
325 {
326     return mp::util::create_APDU(m_odr, type, in_apdu);
327 }
328
329 Z_APDU *mp_util::create_APDU(ODR odr, int type, const Z_APDU *in_apdu)
330 {
331     Z_APDU *out_apdu = zget_APDU(odr, type);
332     transfer_referenceId(odr, in_apdu, out_apdu);
333     return out_apdu;
334 }
335
336 void mp_util::transfer_referenceId(ODR odr, const Z_APDU *src, Z_APDU *dst)
337 {
338     Z_ReferenceId **id_to = mp::util::get_referenceId(dst);
339     *id_to = 0;
340     if (src)
341     {
342         Z_ReferenceId **id_from = mp::util::get_referenceId(src);
343         if (id_from && *id_from && id_to)
344         {
345             *id_to = (Z_ReferenceId*) odr_malloc (odr, sizeof(**id_to));
346             (*id_to)->size = (*id_to)->len = (*id_from)->len;
347             (*id_to)->buf = (unsigned char*) odr_malloc(odr, (*id_to)->len);
348             memcpy((*id_to)->buf, (*id_from)->buf, (*id_to)->len);
349         }
350         else if (id_to)
351             *id_to = 0;
352     }
353 }
354
355 Z_APDU *mp::odr::create_initResponse(const Z_APDU *in_apdu,
356                                      int error, const char *addinfo)
357 {
358     Z_APDU *apdu = create_APDU(Z_APDU_initResponse, in_apdu);
359     if (error)
360     {
361         apdu->u.initResponse->userInformationField =
362             zget_init_diagnostics(m_odr, error, addinfo);
363         *apdu->u.initResponse->result = 0;
364     }
365     return apdu;
366 }
367
368 Z_APDU *mp::odr::create_searchResponse(const Z_APDU *in_apdu,
369                                        int error, const char *addinfo)
370 {
371     Z_APDU *apdu = create_APDU(Z_APDU_searchResponse, in_apdu);
372     if (error)
373     {
374         Z_Records *rec = (Z_Records *) odr_malloc(m_odr, sizeof(Z_Records));
375         *apdu->u.searchResponse->searchStatus = 0;
376         apdu->u.searchResponse->records = rec;
377         rec->which = Z_Records_NSD;
378         rec->u.nonSurrogateDiagnostic =
379             zget_DefaultDiagFormat(m_odr, error, addinfo);
380         
381     }
382     return apdu;
383 }
384
385 Z_APDU *mp::odr::create_presentResponse(const Z_APDU *in_apdu,
386                                         int error, const char *addinfo)
387 {
388     Z_APDU *apdu = create_APDU(Z_APDU_presentResponse, in_apdu);
389     if (error)
390     {
391         Z_Records *rec = (Z_Records *) odr_malloc(m_odr, sizeof(Z_Records));
392         apdu->u.presentResponse->records = rec;
393         
394         rec->which = Z_Records_NSD;
395         rec->u.nonSurrogateDiagnostic =
396             zget_DefaultDiagFormat(m_odr, error, addinfo);
397         *apdu->u.presentResponse->presentStatus = Z_PresentStatus_failure;
398     }
399     return apdu;
400 }
401
402 Z_APDU *mp::odr::create_scanResponse(const Z_APDU *in_apdu,
403                                      int error, const char *addinfo)
404 {
405     Z_APDU *apdu = create_APDU(Z_APDU_scanResponse, in_apdu);
406     Z_ScanResponse *res = apdu->u.scanResponse;
407     res->entries = (Z_ListEntries *) odr_malloc(m_odr, sizeof(*res->entries));
408     res->entries->num_entries = 0;
409     res->entries->entries = 0;
410
411     if (error)
412     {
413         *res->scanStatus = Z_Scan_failure;
414
415         res->entries->num_nonsurrogateDiagnostics = 1;
416         res->entries->nonsurrogateDiagnostics = (Z_DiagRec **)
417             odr_malloc(m_odr, sizeof(Z_DiagRec *));
418         res->entries->nonsurrogateDiagnostics[0] = 
419             zget_DiagRec(m_odr, error, addinfo);
420     }
421     else
422     {
423         res->entries->num_nonsurrogateDiagnostics = 0;
424         res->entries->nonsurrogateDiagnostics = 0;
425     }
426     return apdu;
427 }
428
429 Z_GDU *mp::odr::create_HTTP_Response(mp::Session &session,
430                                      Z_HTTP_Request *hreq, int code)
431 {
432     const char *response_version = "1.0";
433     bool keepalive = false;
434     if (!strcmp(hreq->version, "1.0")) 
435     {
436         const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
437         if (v && !strcmp(v, "Keep-Alive"))
438             keepalive = true;
439         else
440             session.close();
441         response_version = "1.0";
442     }
443     else
444     {
445         const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
446         if (v && !strcmp(v, "close"))
447             session.close();
448         else
449             keepalive = true;
450         response_version = "1.1";
451     }
452
453     Z_GDU *gdu = z_get_HTTP_Response(m_odr, code);
454     Z_HTTP_Response *hres = gdu->u.HTTP_Response;
455     hres->version = odr_strdup(m_odr, response_version);
456     if (keepalive)
457         z_HTTP_header_add(m_odr, &hres->headers, "Connection", "Keep-Alive");
458     
459     return gdu;
460 }
461
462 Z_ReferenceId **mp_util::get_referenceId(const Z_APDU *apdu)
463 {
464     switch (apdu->which)
465     {
466     case  Z_APDU_initRequest:
467         return &apdu->u.initRequest->referenceId; 
468     case  Z_APDU_initResponse:
469         return &apdu->u.initResponse->referenceId;
470     case  Z_APDU_searchRequest:
471         return &apdu->u.searchRequest->referenceId;
472     case  Z_APDU_searchResponse:
473         return &apdu->u.searchResponse->referenceId;
474     case  Z_APDU_presentRequest:
475         return &apdu->u.presentRequest->referenceId;
476     case  Z_APDU_presentResponse:
477         return &apdu->u.presentResponse->referenceId;
478     case  Z_APDU_deleteResultSetRequest:
479         return &apdu->u.deleteResultSetRequest->referenceId;
480     case  Z_APDU_deleteResultSetResponse:
481         return &apdu->u.deleteResultSetResponse->referenceId;
482     case  Z_APDU_accessControlRequest:
483         return &apdu->u.accessControlRequest->referenceId;
484     case  Z_APDU_accessControlResponse:
485         return &apdu->u.accessControlResponse->referenceId;
486     case  Z_APDU_resourceControlRequest:
487         return &apdu->u.resourceControlRequest->referenceId;
488     case  Z_APDU_resourceControlResponse:
489         return &apdu->u.resourceControlResponse->referenceId;
490     case  Z_APDU_triggerResourceControlRequest:
491         return &apdu->u.triggerResourceControlRequest->referenceId;
492     case  Z_APDU_resourceReportRequest:
493         return &apdu->u.resourceReportRequest->referenceId;
494     case  Z_APDU_resourceReportResponse:
495         return &apdu->u.resourceReportResponse->referenceId;
496     case  Z_APDU_scanRequest:
497         return &apdu->u.scanRequest->referenceId;
498     case  Z_APDU_scanResponse:
499         return &apdu->u.scanResponse->referenceId;
500     case  Z_APDU_sortRequest:
501         return &apdu->u.sortRequest->referenceId;
502     case  Z_APDU_sortResponse:
503         return &apdu->u.sortResponse->referenceId;
504     case  Z_APDU_segmentRequest:
505         return &apdu->u.segmentRequest->referenceId;
506     case  Z_APDU_extendedServicesRequest:
507         return &apdu->u.extendedServicesRequest->referenceId;
508     case  Z_APDU_extendedServicesResponse:
509         return &apdu->u.extendedServicesResponse->referenceId;
510     case  Z_APDU_close:
511         return &apdu->u.close->referenceId;
512     }
513     return 0;
514 }
515
516
517 /*
518  * Local variables:
519  * c-basic-offset: 4
520  * indent-tabs-mode: nil
521  * c-file-style: "stroustrup"
522  * End:
523  * vim: shiftwidth=4 tabstop=8 expandtab
524  */