2 * Copyright (c) 1998-2007, Index Data.
3 * See the file LICENSE for details.
5 * $Id: yaz-my-client.cpp,v 1.27 2007-04-12 15:00:33 adam Exp $
10 #include <yaz/options.h>
11 #include <yaz/diagbib1.h>
12 #include <yaz/marcdisp.h>
13 #include <yazpp/ir-assoc.h>
14 #include <yazpp/pdu-assoc.h>
15 #include <yazpp/socket-manager.h>
16 #include <yaz/oid_db.h>
19 #if HAVE_READLINE_READLINE_H
20 #include <readline/readline.h>
22 #if HAVE_READLINE_HISTORY_H
23 #include <readline/history.h>
27 using namespace yazpp_1;
29 class YAZ_EXPORT MyClient : public IR_Assoc {
31 int m_interactive_flag;
32 char m_thisCommand[1024];
33 char m_lastCommand[1024];
35 SocketManager *m_socketManager;
37 MyClient(IPDU_Observable *the_PDU_Observable,
38 SocketManager *the_SocketManager);
39 IPDU_Observer *sessionNotify(
40 IPDU_Observable *the_PDU_Observable, int fd);
41 int args(SocketManager *socketManager, int argc, char **argv);
42 int interactive(SocketManager *socketManager);
44 void recv_initResponse(Z_InitResponse *initResponse);
45 void recv_searchResponse(Z_SearchResponse *searchResponse);
46 void recv_presentResponse(Z_PresentResponse *presentResponse);
47 void recv_records (Z_Records *records);
48 void recv_diagrecs(Z_DiagRec **pp, int num);
49 void recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset);
50 void recv_record(Z_DatabaseRecord *record, int offset,
51 const char *databaseName);
52 void recv_textRecord(const char *buf, size_t len);
53 void recv_genericRecord(Z_GenericRecord *r);
57 char *get_cookie (Z_OtherInformation **oi);
58 int processCommand(const char *cmd);
59 const char *getCommand();
60 int cmd_open(char *host);
61 int cmd_connect(char *host);
62 int cmd_quit(char *args);
63 int cmd_close(char *args);
64 int cmd_find(char *args);
65 int cmd_show(char *args);
66 int cmd_cookie(char *args);
67 int cmd_init(char *args);
68 int cmd_format(char *args);
69 int cmd_proxy(char *args);
73 void MyClient::connectNotify()
75 printf ("Connection accepted by target\n");
79 void MyClient::timeoutNotify()
81 printf ("Connection timeout\n");
85 void MyClient::failNotify()
87 printf ("Connection closed by target\n");
91 IPDU_Observer *MyClient::sessionNotify(IPDU_Observable *the_PDU_Observable,
94 return new MyClient(the_PDU_Observable, m_socketManager);
97 MyClient::MyClient(IPDU_Observable *the_PDU_Observable,
98 SocketManager *the_socketManager) :
99 IR_Assoc (the_PDU_Observable)
102 m_interactive_flag = 1;
103 m_thisCommand[0] = '\0';
104 m_lastCommand[0] = '\0';
105 m_socketManager = the_socketManager;
108 void usage(char *prog)
110 fprintf (stderr, "%s: [-v log] [-c cookie] [-p proxy] [zurl]\n", prog);
114 char *MyClient::get_cookie(Z_OtherInformation **otherInfo)
116 Z_OtherInformationUnit *oi;
119 yaz_string_to_oid(yaz_oid_std(), CLASS_USERINFO, OID_STR_COOKIE);
122 (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
123 oi->which == Z_OtherInfo_characterInfo)
124 return oi->information.characterInfo;
128 void MyClient::recv_initResponse(Z_InitResponse *initResponse)
130 printf ("Got InitResponse. Status ");
131 if (*initResponse->result)
135 const char *p = get_cookie (&initResponse->otherInfo);
138 printf ("cookie = %s\n", p);
146 void MyClient::recv_diagrecs(Z_DiagRec **pp, int num)
149 Z_DefaultDiagFormat *r;
151 printf("Diagnostic message(s) from database:\n");
152 for (i = 0; i<num; i++)
154 Z_DiagRec *p = pp[i];
155 if (p->which != Z_DiagRec_defaultFormat)
157 printf("Diagnostic record not in default format.\n");
161 r = p->u.defaultFormat;
162 printf(" [%d] %s", *r->condition, diagbib1_str(*r->condition));
165 case Z_DefaultDiagFormat_v2Addinfo:
166 printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
168 case Z_DefaultDiagFormat_v3Addinfo:
169 printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
175 void MyClient::recv_textRecord(const char *buf, size_t len)
177 fwrite (buf, 1, len, stdout);
178 fputc ('\n', stdout);
181 void MyClient::recv_genericRecord(Z_GenericRecord *r)
183 WRBUF w = wrbuf_alloc();
184 yaz_display_grs1(w, r, 0);
185 fwrite(wrbuf_buf(w), 1, wrbuf_len(w), stdout);
189 void MyClient::recv_record(Z_DatabaseRecord *record, int offset,
190 const char *databaseName)
192 Z_External *r = (Z_External*) record;
194 * Tell the user what we got.
196 if (r->direct_reference)
198 char name_oid_str[OID_STR_MAX];
199 const char *name_oid = yaz_oid_to_string_buf(r->direct_reference, 0,
201 printf("Record type: %s\n", name_oid ? name_oid : "unknown");
203 if (r->which == Z_External_octet && record->u.octet_aligned->len)
205 if (yaz_oid_is_iso2709(r->direct_reference))
207 yaz_marc_t mt = yaz_marc_create();
209 const char *result_buf;
211 yaz_marc_decode_buf(mt, (const char *)
212 record->u.octet_aligned->buf,
213 record->u.octet_aligned->len,
214 &result_buf, &result_size);
215 fwrite(result_buf, 1, result_size, stdout);
216 yaz_marc_destroy(mt);
220 recv_textRecord((const char *) record->u.octet_aligned->buf,
221 (size_t) record->u.octet_aligned->len);
224 else if (r->which == Z_External_sutrs)
225 recv_textRecord((const char *) r->u.sutrs->buf,
226 (size_t) r->u.sutrs->len);
227 else if (r->which == Z_External_grs1)
228 recv_genericRecord(r->u.grs1);
231 printf("Unknown record representation.\n");
232 if (!z_External(odr_print(), &r, 0, 0))
234 odr_perror(odr_print(), "Printing external");
235 odr_reset(odr_print());
240 void MyClient::recv_namePlusRecord (Z_NamePlusRecord *zpr, int offset)
242 if (zpr->databaseName)
243 printf("[%s]", zpr->databaseName);
244 if (zpr->which == Z_NamePlusRecord_surrogateDiagnostic)
245 recv_diagrecs(&zpr->u.surrogateDiagnostic, 1);
247 recv_record(zpr->u.databaseRecord, offset, zpr->databaseName);
250 void MyClient::recv_records (Z_Records *records)
252 Z_DiagRec dr, *dr_p = &dr;
256 switch (records->which)
258 case Z_Records_DBOSD:
259 for (i = 0; i < records->u.databaseOrSurDiagnostics->num_records; i++)
260 recv_namePlusRecord(records->u.databaseOrSurDiagnostics->
261 records[i], i + m_setOffset);
262 m_setOffset += records->u.databaseOrSurDiagnostics->num_records;
265 dr.which = Z_DiagRec_defaultFormat;
266 dr.u.defaultFormat = records->u.nonSurrogateDiagnostic;
267 recv_diagrecs (&dr_p, 1);
269 case Z_Records_multipleNSD:
270 recv_diagrecs (records->u.multipleNonSurDiagnostics->diagRecs,
271 records->u.multipleNonSurDiagnostics->num_diagRecs);
276 void MyClient::recv_searchResponse(Z_SearchResponse *searchResponse)
278 printf ("Got SearchResponse. Status ");
279 if (!*searchResponse->searchStatus)
286 printf ("Hits: %d\n", *searchResponse->resultCount);
288 recv_records (searchResponse->records);
291 void MyClient::recv_presentResponse(Z_PresentResponse *presentResponse)
293 printf ("Got PresentResponse\n");
294 recv_records (presentResponse->records);
300 while (m_socketManager->processEvent() > 0)
302 if (get_lastReceived())
309 #define C_PROMPT "Z>"
311 int MyClient::cmd_connect(char *host)
320 int MyClient::cmd_open(char *host)
331 int MyClient::cmd_init(char *args)
333 if (send_initRequest() >= 0)
340 int MyClient::cmd_quit(char *args)
345 int MyClient::cmd_close(char *args)
351 int MyClient::cmd_find(char *args)
355 if (query.set_rpn(args) <= 0)
357 printf ("Bad RPN query\n");
360 if (send_searchRequest(&query) >= 0)
363 printf ("Not connected\n");
367 int MyClient::cmd_show(char *args)
369 int start = m_setOffset, number = 1;
371 sscanf (args, "%d %d", &start, &number);
373 if (send_presentRequest(start, number) >= 0)
376 printf ("Not connected\n");
380 int MyClient::cmd_cookie(char *args)
382 set_cookie(*args ? args : 0);
386 int MyClient::cmd_format(char *args)
388 set_preferredRecordSyntax(args);
392 int MyClient::cmd_proxy(char *args)
398 int MyClient::processCommand(const char *commandLine)
400 char cmdStr[1024], cmdArgs[1024];
405 int (MyClient::*fun)(char *arg);
408 {"open", &MyClient::cmd_open, "<host>[':'<port>][/<database>]"},
409 {"connect", &MyClient::cmd_connect, "<host>[':'<port>][/<database>]"},
410 {"quit", &MyClient::cmd_quit, ""},
411 {"close", &MyClient::cmd_close, ""},
412 {"find", &MyClient::cmd_find, "<query>"},
413 {"show", &MyClient::cmd_show, "[<start> [<number>]]"},
414 {"cookie", &MyClient::cmd_cookie, "<cookie>"},
415 {"init", &MyClient::cmd_init, ""},
416 {"format", &MyClient::cmd_format, "<record-syntax>"},
417 {"proxy", &MyClient::cmd_proxy, "<host>:[':'<port>]"},
421 if (sscanf(commandLine, "%s %[^;]", cmdStr, cmdArgs) < 1)
424 for (i = 0; cmd[i].cmd; i++)
425 if (!strncmp(cmd[i].cmd, cmdStr, strlen(cmdStr)))
429 if (cmd[i].cmd) // Invoke command handler
430 res = (this->*cmd[i].fun)(cmdArgs);
431 else // Dump help screen
433 printf("Unknown command: %s.\n", cmdStr);
434 printf("Currently recognized commands:\n");
435 for (i = 0; cmd[i].cmd; i++)
436 printf(" %s %s\n", cmd[i].cmd, cmd[i].ad);
441 const char *MyClient::getCommand()
443 #if HAVE_READLINE_READLINE_H
444 // Read using GNU readline
446 line_in=readline(C_PROMPT);
449 #if HAVE_READLINE_HISTORY_H
451 add_history(line_in);
453 strncpy(m_thisCommand,line_in, 1023);
454 m_thisCommand[1023] = '\0';
457 // Read using fgets(3)
460 if (!fgets(m_thisCommand, 1023, stdin))
463 // Remove trailing whitespace
464 char *cp = m_thisCommand + strlen(m_thisCommand);
465 while (cp != m_thisCommand && strchr("\t \n", cp[-1]))
469 // Remove leading spaces...
470 while (*cp && strchr ("\t \n", *cp))
472 // Save command if non-empty
474 strcpy (m_lastCommand, cp);
475 return m_lastCommand;
478 int MyClient::interactive(SocketManager *socketManager)
481 if (!m_interactive_flag)
483 while ((cmd = getCommand()))
485 if (!processCommand(cmd))
491 int MyClient::args(SocketManager *socketManager, int argc, char **argv)
496 char *prog = argv[0];
499 while ((ret = options("c:p:v:q", argv, argc, &arg)) != -2)
523 yaz_log_init_level (yaz_log_mask_str(arg));
526 m_interactive_flag = 0;
545 int main(int argc, char **argv)
547 SocketManager mySocketManager;
548 PDU_Assoc *some = new PDU_Assoc(&mySocketManager);
550 MyClient z(some, &mySocketManager);
552 if (z.args(&mySocketManager, argc, argv))
554 if (z.interactive(&mySocketManager))
561 * indent-tabs-mode: nil
563 * vim: shiftwidth=4 tabstop=8 expandtab