1 /* This file is part of the yazpp toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
11 #include <yaz/options.h>
12 #include <yaz/diagbib1.h>
13 #include <yaz/marcdisp.h>
14 #include <yazpp/ir-assoc.h>
15 #include <yazpp/pdu-assoc.h>
16 #include <yazpp/socket-manager.h>
17 #include <yaz/oid_db.h>
20 #if HAVE_READLINE_READLINE_H
21 #include <readline/readline.h>
23 #if HAVE_READLINE_HISTORY_H
24 #include <readline/history.h>
28 using namespace yazpp_1;
30 class YAZ_EXPORT MyClient : public IR_Assoc {
32 int m_interactive_flag;
33 char m_thisCommand[1024];
34 char m_lastCommand[1024];
36 SocketManager *m_socketManager;
38 MyClient(IPDU_Observable *the_PDU_Observable,
39 SocketManager *the_SocketManager);
40 IPDU_Observer *sessionNotify(
41 IPDU_Observable *the_PDU_Observable, int fd);
42 int args(SocketManager *socketManager, int argc, char **argv);
43 int interactive(SocketManager *socketManager);
45 void recv_initResponse(Z_InitResponse *initResponse);
46 void recv_searchResponse(Z_SearchResponse *searchResponse);
47 void recv_presentResponse(Z_PresentResponse *presentResponse);
48 void recv_records (Z_Records *records);
49 void recv_diagrecs(Z_DiagRec **pp, int num);
50 void recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset);
51 void recv_record(Z_DatabaseRecord *record, int offset,
52 const char *databaseName);
53 void recv_textRecord(const char *buf, size_t len);
54 void recv_genericRecord(Z_GenericRecord *r);
58 char *get_cookie (Z_OtherInformation **oi);
59 int processCommand(const char *cmd);
60 const char *getCommand();
61 int cmd_open(char *host);
62 int cmd_connect(char *host);
63 int cmd_quit(char *args);
64 int cmd_close(char *args);
65 int cmd_find(char *args);
66 int cmd_show(char *args);
67 int cmd_cookie(char *args);
68 int cmd_init(char *args);
69 int cmd_format(char *args);
70 int cmd_proxy(char *args);
74 void MyClient::connectNotify()
76 printf ("Connection accepted by target\n");
80 void MyClient::timeoutNotify()
82 printf ("Connection timeout\n");
86 void MyClient::failNotify()
88 printf ("Connection closed by target\n");
92 IPDU_Observer *MyClient::sessionNotify(IPDU_Observable *the_PDU_Observable,
95 return new MyClient(the_PDU_Observable, m_socketManager);
98 MyClient::MyClient(IPDU_Observable *the_PDU_Observable,
99 SocketManager *the_socketManager) :
100 IR_Assoc (the_PDU_Observable)
103 m_interactive_flag = 1;
104 m_thisCommand[0] = '\0';
105 m_lastCommand[0] = '\0';
106 m_socketManager = the_socketManager;
109 void usage(char *prog)
111 fprintf (stderr, "%s: [-v log] [-c cookie] [-p proxy] [zurl]\n", prog);
115 char *MyClient::get_cookie(Z_OtherInformation **otherInfo)
117 Z_OtherInformationUnit *oi =
118 update_otherInformation(otherInfo, 0, yaz_oid_userinfo_cookie, 1, 1);
120 if (oi && oi->which == Z_OtherInfo_characterInfo)
121 return oi->information.characterInfo;
125 void MyClient::recv_initResponse(Z_InitResponse *initResponse)
127 printf ("Got InitResponse. Status ");
128 if (*initResponse->result)
132 const char *p = get_cookie (&initResponse->otherInfo);
135 printf ("cookie = %s\n", p);
143 void MyClient::recv_diagrecs(Z_DiagRec **pp, int num)
146 Z_DefaultDiagFormat *r;
148 printf("Diagnostic message(s) from database:\n");
149 for (i = 0; i<num; i++)
151 Z_DiagRec *p = pp[i];
152 if (p->which != Z_DiagRec_defaultFormat)
154 printf("Diagnostic record not in default format.\n");
158 r = p->u.defaultFormat;
159 printf(" [" ODR_INT_PRINTF "] %s", *r->condition, diagbib1_str(*r->condition));
162 case Z_DefaultDiagFormat_v2Addinfo:
163 printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
165 case Z_DefaultDiagFormat_v3Addinfo:
166 printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
172 void MyClient::recv_textRecord(const char *buf, size_t len)
174 fwrite (buf, 1, len, stdout);
175 fputc ('\n', stdout);
178 void MyClient::recv_genericRecord(Z_GenericRecord *r)
180 WRBUF w = wrbuf_alloc();
181 yaz_display_grs1(w, r, 0);
182 fwrite(wrbuf_buf(w), 1, wrbuf_len(w), stdout);
186 void MyClient::recv_record(Z_DatabaseRecord *record, int offset,
187 const char *databaseName)
189 Z_External *r = (Z_External*) record;
191 * Tell the user what we got.
193 if (r->direct_reference)
195 char name_oid_str[OID_STR_MAX];
196 const char *name_oid = yaz_oid_to_string_buf(r->direct_reference, 0,
198 printf("Record type: %s\n", name_oid ? name_oid : "unknown");
200 if (r->which == Z_External_octet && record->u.octet_aligned->len)
202 if (yaz_oid_is_iso2709(r->direct_reference))
204 yaz_marc_t mt = yaz_marc_create();
206 const char *result_buf;
208 yaz_marc_decode_buf(mt, (const char *)
209 record->u.octet_aligned->buf,
210 record->u.octet_aligned->len,
211 &result_buf, &result_size);
212 fwrite(result_buf, 1, result_size, stdout);
213 yaz_marc_destroy(mt);
217 recv_textRecord((const char *) record->u.octet_aligned->buf,
218 (size_t) record->u.octet_aligned->len);
221 else if (r->which == Z_External_sutrs)
222 recv_textRecord((const char *) r->u.sutrs->buf,
223 (size_t) r->u.sutrs->len);
224 else if (r->which == Z_External_grs1)
225 recv_genericRecord(r->u.grs1);
228 printf("Unknown record representation.\n");
229 if (!z_External(odr_print(), &r, 0, 0))
231 odr_perror(odr_print(), "Printing external");
232 odr_reset(odr_print());
237 void MyClient::recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset)
239 if (zpr->databaseName)
240 printf("[%s]", zpr->databaseName);
241 if (zpr->which == Z_NamePlusRecord_surrogateDiagnostic)
242 recv_diagrecs(&zpr->u.surrogateDiagnostic, 1);
244 recv_record(zpr->u.databaseRecord, offset, zpr->databaseName);
247 void MyClient::recv_records (Z_Records *records)
249 Z_DiagRec dr, *dr_p = &dr;
253 switch (records->which)
255 case Z_Records_DBOSD:
256 for (i = 0; i < records->u.databaseOrSurDiagnostics->num_records; i++)
257 recv_namePlusRecord(records->u.databaseOrSurDiagnostics->
258 records[i], i + m_setOffset);
259 m_setOffset += records->u.databaseOrSurDiagnostics->num_records;
262 dr.which = Z_DiagRec_defaultFormat;
263 dr.u.defaultFormat = records->u.nonSurrogateDiagnostic;
264 recv_diagrecs (&dr_p, 1);
266 case Z_Records_multipleNSD:
267 recv_diagrecs (records->u.multipleNonSurDiagnostics->diagRecs,
268 records->u.multipleNonSurDiagnostics->num_diagRecs);
273 void MyClient::recv_searchResponse(Z_SearchResponse *searchResponse)
275 printf ("Got SearchResponse. Status ");
276 if (!*searchResponse->searchStatus)
283 printf ("Hits: " ODR_INT_PRINTF "\n", *searchResponse->resultCount);
285 recv_records (searchResponse->records);
288 void MyClient::recv_presentResponse(Z_PresentResponse *presentResponse)
290 printf ("Got PresentResponse\n");
291 recv_records (presentResponse->records);
297 while (m_socketManager->processEvent() > 0)
299 if (get_lastReceived())
306 #define C_PROMPT "Z>"
308 int MyClient::cmd_connect(char *host)
317 int MyClient::cmd_open(char *host)
328 int MyClient::cmd_init(char *args)
330 if (send_initRequest() >= 0)
337 int MyClient::cmd_quit(char *args)
342 int MyClient::cmd_close(char *args)
348 int MyClient::cmd_find(char *args)
352 if (query.set_rpn(args) <= 0)
354 printf ("Bad RPN query\n");
357 if (send_searchRequest(&query) >= 0)
360 printf ("Not connected\n");
364 int MyClient::cmd_show(char *args)
366 int start = m_setOffset, number = 1;
368 sscanf (args, "%d %d", &start, &number);
370 if (send_presentRequest(start, number) >= 0)
373 printf ("Not connected\n");
377 int MyClient::cmd_cookie(char *args)
379 set_cookie(*args ? args : 0);
383 int MyClient::cmd_format(char *args)
385 set_preferredRecordSyntax(args);
389 int MyClient::cmd_proxy(char *args)
395 int MyClient::processCommand(const char *commandLine)
397 char cmdStr[1024], cmdArgs[1024];
402 int (MyClient::*fun)(char *arg);
405 {"open", &MyClient::cmd_open, "<host>[':'<port>][/<database>]"},
406 {"connect", &MyClient::cmd_connect, "<host>[':'<port>][/<database>]"},
407 {"quit", &MyClient::cmd_quit, ""},
408 {"close", &MyClient::cmd_close, ""},
409 {"find", &MyClient::cmd_find, "<query>"},
410 {"show", &MyClient::cmd_show, "[<start> [<number>]]"},
411 {"cookie", &MyClient::cmd_cookie, "<cookie>"},
412 {"init", &MyClient::cmd_init, ""},
413 {"format", &MyClient::cmd_format, "<record-syntax>"},
414 {"proxy", &MyClient::cmd_proxy, "<host>:[':'<port>]"},
418 if (sscanf(commandLine, "%s %[^;]", cmdStr, cmdArgs) < 1)
421 for (i = 0; cmd[i].cmd; i++)
422 if (!strncmp(cmd[i].cmd, cmdStr, strlen(cmdStr)))
426 if (cmd[i].cmd) // Invoke command handler
427 res = (this->*cmd[i].fun)(cmdArgs);
428 else // Dump help screen
430 printf("Unknown command: %s.\n", cmdStr);
431 printf("Currently recognized commands:\n");
432 for (i = 0; cmd[i].cmd; i++)
433 printf(" %s %s\n", cmd[i].cmd, cmd[i].ad);
438 const char *MyClient::getCommand()
440 #if HAVE_READLINE_READLINE_H
441 // Read using GNU readline
443 line_in=readline(C_PROMPT);
446 #if HAVE_READLINE_HISTORY_H
448 add_history(line_in);
450 strncpy(m_thisCommand,line_in, 1023);
451 m_thisCommand[1023] = '\0';
454 // Read using fgets(3)
457 if (!fgets(m_thisCommand, 1023, stdin))
460 // Remove trailing whitespace
461 char *cp = m_thisCommand + strlen(m_thisCommand);
462 while (cp != m_thisCommand && strchr("\t \n", cp[-1]))
466 // Remove leading spaces...
467 while (*cp && strchr ("\t \n", *cp))
469 // Save command if non-empty
471 strcpy (m_lastCommand, cp);
472 return m_lastCommand;
475 int MyClient::interactive(SocketManager *socketManager)
478 if (!m_interactive_flag)
480 while ((cmd = getCommand()))
482 if (!processCommand(cmd))
488 int MyClient::args(SocketManager *socketManager, int argc, char **argv)
493 char *prog = argv[0];
496 while ((ret = options("c:p:v:q", argv, argc, &arg)) != -2)
520 yaz_log_init_level (yaz_log_mask_str(arg));
523 m_interactive_flag = 0;
542 int main(int argc, char **argv)
544 SocketManager mySocketManager;
545 PDU_Assoc *some = new PDU_Assoc(&mySocketManager);
547 MyClient z(some, &mySocketManager);
549 if (z.args(&mySocketManager, argc, argv))
551 if (z.interactive(&mySocketManager))
558 * c-file-style: "Stroustrup"
559 * indent-tabs-mode: nil
561 * vim: shiftwidth=4 tabstop=8 expandtab