Moved header files to include/yaz++. Switched to libtool and automake.
[yazpp-moved-to-github.git] / src / yaz-z-assoc.cpp
1 /*
2  * Copyright (c) 1998-2000, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Log: yaz-z-assoc.cpp,v $
6  * Revision 1.15  2000-10-11 11:58:17  adam
7  * Moved header files to include/yaz++. Switched to libtool and automake.
8  * Configure script creates yaz++-config script.
9  *
10  * Revision 1.14  2000/09/12 16:40:33  heikki
11  * minor
12  *
13  * Revision 1.13  2000/09/08 10:23:42  adam
14  * Added skeleton of yaz-z-server.
15  *
16  * Revision 1.12  2000/09/05 13:57:28  adam
17  * Fixed get_otherInfoAPDU to return otherInfo for extended services.
18  *
19  * Revision 1.11  2000/09/04 08:59:16  adam
20  * Changed call to logging functions (yaz_ added).
21  *
22  * Revision 1.10  2000/09/04 08:29:22  adam
23  * Fixed memory leak(s). Added re-use of associations, rather than
24  * re-init, when maximum number of targets are in use.
25  *
26  * Revision 1.9  2000/08/10 08:42:42  adam
27  * Fixes for {set,get}_APDU_log.
28  *
29  * Revision 1.8  2000/08/07 14:19:59  adam
30  * Fixed serious bug regarding timeouts. Improved logging for proxy.
31  *
32  * Revision 1.7  2000/05/10 11:36:58  ian
33  * Added default parameters for refid to request functions.
34  * Added default parameter for result set name to search and present request.
35  * Commented out forced logging of PDU contents.
36  * Added send_deleteResultSetRequest
37  *
38  * Revision 1.6  1999/12/06 13:52:45  adam
39  * Modified for new location of YAZ header files. Experimental threaded
40  * operation.
41  *
42  * Revision 1.5  1999/11/10 10:02:34  adam
43  * Work on proxy.
44  *
45  * Revision 1.4  1999/09/13 12:53:44  adam
46  * Proxy removes OtherInfo Proxy Address and Session ID. Other
47  * Otherinfo remains untouched.
48  *
49  * Revision 1.3  1999/04/21 12:09:01  adam
50  * Many improvements. Modified to proxy server to work with "sessions"
51  * based on cookies.
52  *
53  * Revision 1.2  1999/04/20 10:30:05  adam
54  * Implemented various stuff for client and proxy. Updated calls
55  * to ODR to reflect new name parameter.
56  *
57  * Revision 1.1  1999/04/09 11:46:57  adam
58  * Added object Yaz_Z_Assoc. Much more functional client.
59  *
60  */
61
62 #include <assert.h>
63
64 #include <yaz/log.h>
65 #include <yaz++/yaz-z-assoc.h>
66 #include <yaz/otherinfo.h>
67
68 int Yaz_Z_Assoc::yaz_init_func()
69 {
70     nmem_init();
71     return 1;
72 }
73
74 int Yaz_Z_Assoc::yaz_init_flag =  Yaz_Z_Assoc::yaz_init_func();  
75
76 Yaz_Z_Assoc::Yaz_Z_Assoc(IYaz_PDU_Observable *the_PDU_Observable)
77 {
78     m_PDU_Observable = the_PDU_Observable;
79     m_odr_in = odr_createmem (ODR_DECODE);
80     m_odr_out = odr_createmem (ODR_ENCODE);
81     m_odr_print = odr_createmem (ODR_PRINT);
82     m_log = LOG_DEBUG;
83     m_APDU_file = 0;
84     m_APDU_fname = 0;
85     m_hostname = 0;
86 }
87
88 void Yaz_Z_Assoc::set_APDU_log(const char *fname)
89 {
90     if (m_APDU_file && m_APDU_file != stderr)
91     {
92         fclose (m_APDU_file);
93         m_APDU_file = 0;
94     }
95     delete [] m_APDU_fname;
96     m_APDU_fname = 0;
97
98     if (fname) 
99     {
100         m_APDU_fname = new char[strlen(fname)+1];
101         strcpy (m_APDU_fname, fname);
102         if (*fname && strcmp(fname, "-"))
103             m_APDU_file = fopen (fname, "a");
104         else
105             m_APDU_file = stderr;
106         odr_setprint(m_odr_print, m_APDU_file);
107     }
108 }
109
110 const char *Yaz_Z_Assoc::get_APDU_log()
111 {
112     return m_APDU_fname;
113 }
114
115 Yaz_Z_Assoc::~Yaz_Z_Assoc()
116 {
117     m_PDU_Observable->destroy();  
118     delete m_PDU_Observable;
119     odr_destroy (m_odr_print);     // note: also runs fclose on m_APDU_file ..
120     odr_destroy (m_odr_out);
121     odr_destroy (m_odr_in);
122     delete [] m_APDU_fname;
123     delete [] m_hostname;
124 }
125
126 void Yaz_Z_Assoc::recv_PDU(const char *buf, int len)
127 {
128     logf (m_log, "recv_PDU len=%d", len);
129     Z_APDU *apdu = decode_Z_PDU (buf, len);
130     if (apdu)
131     {
132         recv_Z_PDU (apdu);
133     }
134 }
135
136 Z_APDU *Yaz_Z_Assoc::create_Z_PDU(int type)
137 {
138     Z_APDU *apdu = zget_APDU(m_odr_out, type);
139     if (apdu->which == Z_APDU_initRequest)
140     {
141         Z_InitRequest * p = apdu->u.initRequest;
142         char *newName = (char*) odr_malloc(m_odr_out, 50);
143         strcpy (newName, p->implementationName);
144         strcat (newName, " YAZ++");
145         p->implementationName = newName;
146     }
147     return apdu;
148 }
149
150 int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu)
151 {
152     char *buf;
153     int len;
154     if (encode_Z_PDU(apdu, &buf, &len) > 0)
155         return m_PDU_Observable->send_PDU(buf, len);
156     return -1;
157 }
158
159 Z_APDU *Yaz_Z_Assoc::decode_Z_PDU(const char *buf, int len)
160 {
161     Z_APDU *apdu;
162
163     odr_reset (m_odr_in);
164     odr_setbuf (m_odr_in, (char*) buf, len, 0);
165
166     if (!z_APDU(m_odr_in, &apdu, 0, 0))
167     {
168         logf(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
169              odr_errmsg(odr_geterror(m_odr_in)),
170              odr_offset(m_odr_in));
171         logf(LOG_LOG, "PDU dump:");
172         odr_dumpBER(yaz_log_file(), buf, len);
173         return 0;
174     }
175     else
176     {
177         if (m_APDU_file)
178             z_APDU(m_odr_print, &apdu, 0, "decode");
179         return apdu;
180     }
181 }
182
183 int Yaz_Z_Assoc::encode_Z_PDU(Z_APDU *apdu, char **buf, int *len)
184 {
185     if (!z_APDU(m_odr_out, &apdu, 0, 0))
186     {
187         logf (LOG_LOG, "yaz_Z_Assoc::encode_Z_PDU failed");
188         return -1;
189     }
190     if (m_APDU_file)
191         z_APDU(m_odr_print, &apdu, 0, "encode");
192     *buf = odr_getbuf (m_odr_out, len, 0);
193     odr_reset (m_odr_out);
194     return *len;
195 }
196
197 const char *Yaz_Z_Assoc::get_hostname()
198 {
199     return m_hostname;
200 }
201
202 void Yaz_Z_Assoc::client(const char *addr)
203 {
204     delete [] m_hostname;
205     m_hostname = new char[strlen(addr)+1];
206     strcpy (m_hostname, addr);
207     m_PDU_Observable->connect (this, addr);
208 }
209
210 void Yaz_Z_Assoc::close()
211 {
212     m_PDU_Observable->close ();
213 }
214
215 void Yaz_Z_Assoc::server(const char *addr)
216 {
217     delete [] m_hostname;
218     m_hostname = new char[strlen(addr)+1];
219     strcpy (m_hostname, addr);
220     m_PDU_Observable->listen (this, addr);
221 }
222
223 ODR Yaz_Z_Assoc::odr_encode()
224 {
225     return m_odr_out;
226 }
227
228 ODR Yaz_Z_Assoc::odr_decode()
229 {
230     return m_odr_in;
231 }
232 ODR Yaz_Z_Assoc::odr_print()
233 {
234     return m_odr_print;
235 }
236
237 void Yaz_Z_Assoc::timeout(int timeout)
238 {
239     m_PDU_Observable->idleTime(timeout);
240 }
241
242 void Yaz_Z_Assoc::get_otherInfoAPDU(Z_APDU *apdu, Z_OtherInformation ***oip)
243 {
244     switch (apdu->which)
245     {
246     case Z_APDU_initRequest:
247         *oip = &apdu->u.initRequest->otherInfo;
248         break;
249     case Z_APDU_searchRequest:
250         *oip = &apdu->u.searchRequest->otherInfo;
251         break;
252     case Z_APDU_presentRequest:
253         *oip = &apdu->u.presentRequest->otherInfo;
254         break;
255     case Z_APDU_sortRequest:
256         *oip = &apdu->u.sortRequest->otherInfo;
257         break;
258     case Z_APDU_scanRequest:
259         *oip = &apdu->u.scanRequest->otherInfo;
260         break;
261     case Z_APDU_extendedServicesRequest:
262         *oip = &apdu->u.extendedServicesRequest->otherInfo;
263         break;
264     case Z_APDU_deleteResultSetRequest:
265         *oip = &apdu->u.deleteResultSetRequest->otherInfo;
266         break;
267     case Z_APDU_initResponse:
268         *oip = &apdu->u.initResponse->otherInfo;
269         break;
270     case Z_APDU_searchResponse:
271         *oip = &apdu->u.searchResponse->otherInfo;
272         break;
273     case Z_APDU_presentResponse:
274         *oip = &apdu->u.presentResponse->otherInfo;
275         break;
276     case Z_APDU_sortResponse:
277         *oip = &apdu->u.sortResponse->otherInfo;
278         break;
279     case Z_APDU_scanResponse:
280         *oip = &apdu->u.scanResponse->otherInfo;
281         break;
282     case Z_APDU_extendedServicesResponse:
283         *oip = &apdu->u.extendedServicesResponse->otherInfo;
284         break;
285     case Z_APDU_deleteResultSetResponse:
286         *oip = &apdu->u.deleteResultSetResponse->otherInfo;
287         break;
288     default:
289         *oip = 0;
290         break;
291     }
292 }
293
294 void Yaz_Z_Assoc::set_otherInformationString (
295     Z_APDU *apdu,
296     int oidval, int categoryValue,
297     const char *str)
298 {
299     Z_OtherInformation **otherInformation;
300     get_otherInfoAPDU(apdu, &otherInformation);
301     if (!otherInformation)
302         return;
303     set_otherInformationString(otherInformation, oidval, categoryValue, str);
304 }
305
306 void Yaz_Z_Assoc::set_otherInformationString (
307     Z_OtherInformation **otherInformation,
308     int oidval, int categoryValue,
309     const char *str)
310 {
311     int oid[OID_SIZE];
312     struct oident ent;
313     ent.proto = PROTO_Z3950;
314     ent.oclass = CLASS_USERINFO;
315     ent.value = (oid_value) oidval;
316     if (!oid_ent_to_oid (&ent, oid))
317         return ;
318     set_otherInformationString(otherInformation, oid, categoryValue, str);
319 }
320
321 void Yaz_Z_Assoc::set_otherInformationString (
322     Z_OtherInformation **otherInformation,
323     int *oid, int categoryValue, const char *str)
324 {
325     Z_OtherInformationUnit *oi =
326         update_otherInformation(otherInformation, 1, oid, categoryValue, 0);
327     if (!oi)
328         return;
329     oi->information.characterInfo = odr_strdup (odr_encode(), str);
330 }
331
332 Z_OtherInformationUnit *Yaz_Z_Assoc::update_otherInformation (
333     Z_OtherInformation **otherInformationP, int createFlag,
334     int *oid, int categoryValue, int deleteFlag)
335 {
336     return yaz_oi_update (otherInformationP,
337                           (createFlag ? odr_encode() : 0),
338                           oid, categoryValue, deleteFlag);
339 }
340
341 Z_ReferenceId* Yaz_Z_Assoc::getRefID(char* str)
342 {
343     Z_ReferenceId* id = NULL;
344
345     if ( str )
346     {
347         id = (Z_ReferenceId*) odr_malloc (m_odr_out, sizeof(*id));
348         id->size = id->len = strlen(str);
349         id->buf = (unsigned char *) str;
350     }
351
352     return id;
353 }
354