1 /* This file is part of the yazpp toolkit.
2 * Copyright (C) 1998-2010 Index Data and Mike Taylor
3 * See the file LICENSE for details.
8 #include <yaz/options.h>
9 #include <yaz/diagbib1.h>
10 #include <yaz/marcdisp.h>
11 #include <yazpp/ir-assoc.h>
12 #include <yazpp/pdu-assoc.h>
13 #include <yazpp/socket-manager.h>
14 #include <yaz/oid_db.h>
17 #if HAVE_READLINE_READLINE_H
18 #include <readline/readline.h>
20 #if HAVE_READLINE_HISTORY_H
21 #include <readline/history.h>
25 using namespace yazpp_1;
27 class YAZ_EXPORT MyClient : public IR_Assoc {
29 int m_interactive_flag;
30 char m_thisCommand[1024];
31 char m_lastCommand[1024];
33 SocketManager *m_socketManager;
35 MyClient(IPDU_Observable *the_PDU_Observable,
36 SocketManager *the_SocketManager);
37 IPDU_Observer *sessionNotify(
38 IPDU_Observable *the_PDU_Observable, int fd);
39 int args(SocketManager *socketManager, int argc, char **argv);
40 int interactive(SocketManager *socketManager);
42 void recv_initResponse(Z_InitResponse *initResponse);
43 void recv_searchResponse(Z_SearchResponse *searchResponse);
44 void recv_presentResponse(Z_PresentResponse *presentResponse);
45 void recv_records (Z_Records *records);
46 void recv_diagrecs(Z_DiagRec **pp, int num);
47 void recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset);
48 void recv_record(Z_DatabaseRecord *record, int offset,
49 const char *databaseName);
50 void recv_textRecord(const char *buf, size_t len);
51 void recv_genericRecord(Z_GenericRecord *r);
55 char *get_cookie (Z_OtherInformation **oi);
56 int processCommand(const char *cmd);
57 const char *getCommand();
58 int cmd_open(char *host);
59 int cmd_connect(char *host);
60 int cmd_quit(char *args);
61 int cmd_close(char *args);
62 int cmd_find(char *args);
63 int cmd_show(char *args);
64 int cmd_cookie(char *args);
65 int cmd_init(char *args);
66 int cmd_format(char *args);
67 int cmd_proxy(char *args);
71 void MyClient::connectNotify()
73 printf ("Connection accepted by target\n");
77 void MyClient::timeoutNotify()
79 printf ("Connection timeout\n");
83 void MyClient::failNotify()
85 printf ("Connection closed by target\n");
89 IPDU_Observer *MyClient::sessionNotify(IPDU_Observable *the_PDU_Observable,
92 return new MyClient(the_PDU_Observable, m_socketManager);
95 MyClient::MyClient(IPDU_Observable *the_PDU_Observable,
96 SocketManager *the_socketManager) :
97 IR_Assoc (the_PDU_Observable)
100 m_interactive_flag = 1;
101 m_thisCommand[0] = '\0';
102 m_lastCommand[0] = '\0';
103 m_socketManager = the_socketManager;
106 void usage(char *prog)
108 fprintf (stderr, "%s: [-v log] [-c cookie] [-p proxy] [zurl]\n", prog);
112 char *MyClient::get_cookie(Z_OtherInformation **otherInfo)
114 Z_OtherInformationUnit *oi =
115 update_otherInformation(otherInfo, 0, yaz_oid_userinfo_cookie, 1, 1);
117 if (oi && oi->which == Z_OtherInfo_characterInfo)
118 return oi->information.characterInfo;
122 void MyClient::recv_initResponse(Z_InitResponse *initResponse)
124 printf ("Got InitResponse. Status ");
125 if (*initResponse->result)
129 const char *p = get_cookie (&initResponse->otherInfo);
132 printf ("cookie = %s\n", p);
140 void MyClient::recv_diagrecs(Z_DiagRec **pp, int num)
143 Z_DefaultDiagFormat *r;
145 printf("Diagnostic message(s) from database:\n");
146 for (i = 0; i<num; i++)
148 Z_DiagRec *p = pp[i];
149 if (p->which != Z_DiagRec_defaultFormat)
151 printf("Diagnostic record not in default format.\n");
155 r = p->u.defaultFormat;
156 printf(" [" ODR_INT_PRINTF "] %s", *r->condition, diagbib1_str(*r->condition));
159 case Z_DefaultDiagFormat_v2Addinfo:
160 printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
162 case Z_DefaultDiagFormat_v3Addinfo:
163 printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
169 void MyClient::recv_textRecord(const char *buf, size_t len)
171 fwrite (buf, 1, len, stdout);
172 fputc ('\n', stdout);
175 void MyClient::recv_genericRecord(Z_GenericRecord *r)
177 WRBUF w = wrbuf_alloc();
178 yaz_display_grs1(w, r, 0);
179 fwrite(wrbuf_buf(w), 1, wrbuf_len(w), stdout);
183 void MyClient::recv_record(Z_DatabaseRecord *record, int offset,
184 const char *databaseName)
186 Z_External *r = (Z_External*) record;
188 * Tell the user what we got.
190 if (r->direct_reference)
192 char name_oid_str[OID_STR_MAX];
193 const char *name_oid = yaz_oid_to_string_buf(r->direct_reference, 0,
195 printf("Record type: %s\n", name_oid ? name_oid : "unknown");
197 if (r->which == Z_External_octet && record->u.octet_aligned->len)
199 if (yaz_oid_is_iso2709(r->direct_reference))
201 yaz_marc_t mt = yaz_marc_create();
203 const char *result_buf;
205 yaz_marc_decode_buf(mt, (const char *)
206 record->u.octet_aligned->buf,
207 record->u.octet_aligned->len,
208 &result_buf, &result_size);
209 fwrite(result_buf, 1, result_size, stdout);
210 yaz_marc_destroy(mt);
214 recv_textRecord((const char *) record->u.octet_aligned->buf,
215 (size_t) record->u.octet_aligned->len);
218 else if (r->which == Z_External_sutrs)
219 recv_textRecord((const char *) r->u.sutrs->buf,
220 (size_t) r->u.sutrs->len);
221 else if (r->which == Z_External_grs1)
222 recv_genericRecord(r->u.grs1);
225 printf("Unknown record representation.\n");
226 if (!z_External(odr_print(), &r, 0, 0))
228 odr_perror(odr_print(), "Printing external");
229 odr_reset(odr_print());
234 void MyClient::recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset)
236 if (zpr->databaseName)
237 printf("[%s]", zpr->databaseName);
238 if (zpr->which == Z_NamePlusRecord_surrogateDiagnostic)
239 recv_diagrecs(&zpr->u.surrogateDiagnostic, 1);
241 recv_record(zpr->u.databaseRecord, offset, zpr->databaseName);
244 void MyClient::recv_records (Z_Records *records)
246 Z_DiagRec dr, *dr_p = &dr;
250 switch (records->which)
252 case Z_Records_DBOSD:
253 for (i = 0; i < records->u.databaseOrSurDiagnostics->num_records; i++)
254 recv_namePlusRecord(records->u.databaseOrSurDiagnostics->
255 records[i], i + m_setOffset);
256 m_setOffset += records->u.databaseOrSurDiagnostics->num_records;
259 dr.which = Z_DiagRec_defaultFormat;
260 dr.u.defaultFormat = records->u.nonSurrogateDiagnostic;
261 recv_diagrecs (&dr_p, 1);
263 case Z_Records_multipleNSD:
264 recv_diagrecs (records->u.multipleNonSurDiagnostics->diagRecs,
265 records->u.multipleNonSurDiagnostics->num_diagRecs);
270 void MyClient::recv_searchResponse(Z_SearchResponse *searchResponse)
272 printf ("Got SearchResponse. Status ");
273 if (!*searchResponse->searchStatus)
280 printf ("Hits: " ODR_INT_PRINTF "\n", *searchResponse->resultCount);
282 recv_records (searchResponse->records);
285 void MyClient::recv_presentResponse(Z_PresentResponse *presentResponse)
287 printf ("Got PresentResponse\n");
288 recv_records (presentResponse->records);
294 while (m_socketManager->processEvent() > 0)
296 if (get_lastReceived())
303 #define C_PROMPT "Z>"
305 int MyClient::cmd_connect(char *host)
314 int MyClient::cmd_open(char *host)
325 int MyClient::cmd_init(char *args)
327 if (send_initRequest() >= 0)
334 int MyClient::cmd_quit(char *args)
339 int MyClient::cmd_close(char *args)
345 int MyClient::cmd_find(char *args)
349 if (query.set_rpn(args) <= 0)
351 printf ("Bad RPN query\n");
354 if (send_searchRequest(&query) >= 0)
357 printf ("Not connected\n");
361 int MyClient::cmd_show(char *args)
363 int start = m_setOffset, number = 1;
365 sscanf (args, "%d %d", &start, &number);
367 if (send_presentRequest(start, number) >= 0)
370 printf ("Not connected\n");
374 int MyClient::cmd_cookie(char *args)
376 set_cookie(*args ? args : 0);
380 int MyClient::cmd_format(char *args)
382 set_preferredRecordSyntax(args);
386 int MyClient::cmd_proxy(char *args)
392 int MyClient::processCommand(const char *commandLine)
394 char cmdStr[1024], cmdArgs[1024];
399 int (MyClient::*fun)(char *arg);
402 {"open", &MyClient::cmd_open, "<host>[':'<port>][/<database>]"},
403 {"connect", &MyClient::cmd_connect, "<host>[':'<port>][/<database>]"},
404 {"quit", &MyClient::cmd_quit, ""},
405 {"close", &MyClient::cmd_close, ""},
406 {"find", &MyClient::cmd_find, "<query>"},
407 {"show", &MyClient::cmd_show, "[<start> [<number>]]"},
408 {"cookie", &MyClient::cmd_cookie, "<cookie>"},
409 {"init", &MyClient::cmd_init, ""},
410 {"format", &MyClient::cmd_format, "<record-syntax>"},
411 {"proxy", &MyClient::cmd_proxy, "<host>:[':'<port>]"},
415 if (sscanf(commandLine, "%s %[^;]", cmdStr, cmdArgs) < 1)
418 for (i = 0; cmd[i].cmd; i++)
419 if (!strncmp(cmd[i].cmd, cmdStr, strlen(cmdStr)))
423 if (cmd[i].cmd) // Invoke command handler
424 res = (this->*cmd[i].fun)(cmdArgs);
425 else // Dump help screen
427 printf("Unknown command: %s.\n", cmdStr);
428 printf("Currently recognized commands:\n");
429 for (i = 0; cmd[i].cmd; i++)
430 printf(" %s %s\n", cmd[i].cmd, cmd[i].ad);
435 const char *MyClient::getCommand()
437 #if HAVE_READLINE_READLINE_H
438 // Read using GNU readline
440 line_in=readline(C_PROMPT);
443 #if HAVE_READLINE_HISTORY_H
445 add_history(line_in);
447 strncpy(m_thisCommand,line_in, 1023);
448 m_thisCommand[1023] = '\0';
451 // Read using fgets(3)
454 if (!fgets(m_thisCommand, 1023, stdin))
457 // Remove trailing whitespace
458 char *cp = m_thisCommand + strlen(m_thisCommand);
459 while (cp != m_thisCommand && strchr("\t \n", cp[-1]))
463 // Remove leading spaces...
464 while (*cp && strchr ("\t \n", *cp))
466 // Save command if non-empty
468 strcpy (m_lastCommand, cp);
469 return m_lastCommand;
472 int MyClient::interactive(SocketManager *socketManager)
475 if (!m_interactive_flag)
477 while ((cmd = getCommand()))
479 if (!processCommand(cmd))
485 int MyClient::args(SocketManager *socketManager, int argc, char **argv)
490 char *prog = argv[0];
493 while ((ret = options("c:p:v:q", argv, argc, &arg)) != -2)
517 yaz_log_init_level (yaz_log_mask_str(arg));
520 m_interactive_flag = 0;
539 int main(int argc, char **argv)
541 SocketManager mySocketManager;
542 PDU_Assoc *some = new PDU_Assoc(&mySocketManager);
544 MyClient z(some, &mySocketManager);
546 if (z.args(&mySocketManager, argc, argv))
548 if (z.interactive(&mySocketManager))
555 * c-file-style: "Stroustrup"
556 * indent-tabs-mode: nil
558 * vim: shiftwidth=4 tabstop=8 expandtab