Added object Yaz_Z_Assoc. Much more functional client.
[yazpp-moved-to-github.git] / src / yaz-client.cpp
1 /*
2  * Copyright (c) 1998-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  * 
6  * $Log: yaz-client.cpp,v $
7  * Revision 1.5  1999-04-09 11:46:57  adam
8  * Added object Yaz_Z_Assoc. Much more functional client.
9  *
10  * Revision 1.4  1999/03/23 14:17:57  adam
11  * More work on timeout handling. Work on yaz-client.
12  *
13  * Revision 1.3  1999/02/02 14:01:18  adam
14  * First WIN32 port of YAZ++.
15  *
16  * Revision 1.2  1999/01/28 13:08:42  adam
17  * Yaz_PDU_Assoc better encapsulated. Memory leak fix in
18  * yaz-socket-manager.cc.
19  *
20  * Revision 1.1.1.1  1999/01/28 09:41:07  adam
21  * First implementation of YAZ++.
22  *
23  */
24
25 #include <log.h>
26 #include <options.h>
27 #include <yaz-ir-assoc.h>
28 #include <yaz-pdu-assoc.h>
29 #include <yaz-socket-manager.h>
30
31 extern "C" {
32 #if HAVE_READLINE_READLINE_H
33 #include <readline/readline.h>
34 #endif
35 #if HAVE_READLINE_HISTORY_H
36 #include <readline/history.h>
37 #endif
38 }
39
40 class YAZ_EXPORT MyClient : public Yaz_IR_Assoc {
41 private:
42     int m_interactive_flag;
43     char m_thisCommand[1024];
44     char m_lastCommand[1024];
45     Yaz_SocketManager *m_socketManager;
46 public:
47     MyClient(IYaz_PDU_Observable *the_PDU_Observable,
48              Yaz_SocketManager *the_SocketManager);
49     IYaz_PDU_Observer *clone(IYaz_PDU_Observable *the_PDU_Observable);
50     int args(Yaz_SocketManager *socketManager, int argc, char **argv);
51     int interactive(Yaz_SocketManager *socketManager);
52     int wait();
53     void recv_initResponse(Z_InitResponse *initResponse);
54     void recv_searchResponse(Z_SearchResponse *searchResponse);
55     int processCommand(const char *cmd);
56     const char *MyClient::getCommand();
57     int cmd_open(char *host);
58     int cmd_quit(char *args);
59     int cmd_close(char *args);
60     int cmd_find(char *args);
61 };
62
63 IYaz_PDU_Observer *MyClient::clone(IYaz_PDU_Observable *the_PDU_Observable)
64 {
65     return new MyClient(the_PDU_Observable, m_socketManager);
66 }
67
68 MyClient::MyClient(IYaz_PDU_Observable *the_PDU_Observable,
69                    Yaz_SocketManager *the_socketManager) :
70     Yaz_IR_Assoc (the_PDU_Observable)
71 {
72     m_interactive_flag = 1;
73     m_thisCommand[0] = '\0';
74     m_lastCommand[0] = '\0';
75     m_socketManager = the_socketManager;
76 }
77
78 void usage(char *prog)
79 {
80     fprintf (stderr, "%s: [-v log] [-p proxy] [zurl]\n", prog);
81     exit (1);
82 }
83
84 void MyClient::recv_initResponse(Z_InitResponse *initResponse)
85 {
86     printf ("Got InitResponse. Status ");
87     if (*initResponse->result)
88         printf ("Ok\n");
89     else
90         printf ("Fail\n");
91 }
92
93 void MyClient::recv_searchResponse(Z_SearchResponse *searchResponse)
94 {
95     printf ("Got SearchResponse. Status ");
96     if (!*searchResponse->searchStatus)
97     {
98         printf ("Fail\n");
99         return;
100     }
101     printf ("Ok\n");
102     printf ("Hits: %d\n", *searchResponse->resultCount);
103 }
104
105 int MyClient::wait()
106 {
107     set_lastReceived(0);
108     while (m_socketManager->processEvent() > 0)
109     {
110         if (get_lastReceived())
111             return 1;
112     }
113     return 0;
114 }
115
116 #define C_PROMPT "Z>"
117
118 int MyClient::cmd_open(char *host)
119 {
120     client (host);
121     if (send_initRequest() >= 0)
122         wait();
123     else
124         close();
125     return 1;
126 }
127
128 int MyClient::cmd_quit(char *args)
129 {
130     return 0;
131 }
132
133 int MyClient::cmd_close(char *args)
134 {
135     close();
136     return 1;
137 }
138
139 int MyClient::cmd_find(char *args)
140 {
141     Yaz_Z_Query query;
142
143     if (query.set_rpn(args) <= 0)
144     {
145         printf ("Bad RPN query\n");
146         return 1;
147     }
148     if (send_searchRequest(&query) >= 0)
149         wait();
150     return 1;
151 }
152
153 int MyClient::processCommand(const char *commandLine)
154 {
155     char cmdStr[1024], cmdArgs[1024];
156     cmdArgs[0] = '\0';
157     cmdStr[0] = '\0';
158     static struct {
159         char *cmd;
160         int (MyClient::*fun)(char *arg);
161         char *ad;
162     } cmd[] = {
163         {"open", &cmd_open, "('tcp'|'osi')':'[<tsel>'/']<host>[':'<port>]"},
164         {"quit", &cmd_quit, ""},
165         {"close", &cmd_close, ""},
166         {"find", &cmd_find, ""},
167         {0,0,0}
168     };
169     
170     if (sscanf(commandLine, "%s %[^;]", cmdStr, cmdArgs) < 1)
171         return 1;
172     int i;
173     for (i = 0; cmd[i].cmd; i++)
174         if (!strncmp(cmd[i].cmd, cmdStr, strlen(cmdStr)))
175             break;
176     
177     int res = 1;
178     if (cmd[i].cmd) // Invoke command handler
179         res = (this->*cmd[i].fun)(cmdArgs);
180     else            // Dump help screen
181     {
182         printf("Unknown command: %s.\n", cmdStr);
183         printf("Currently recognized commands:\n");
184         for (i = 0; cmd[i].cmd; i++)
185             printf("   %s %s\n", cmd[i].cmd, cmd[i].ad);
186     }
187     return res;
188 }
189
190 const char *MyClient::getCommand()
191 {
192 #if HAVE_READLINE_READLINE_H
193     // Read using GNU readline
194     char *line_in;
195     line_in=readline(C_PROMPT);
196     if (!line_in)
197         return 0;
198 #if HAVE_READLINE_HISTORY_H
199     if (*line_in)
200         add_history(line_in);
201 #endif
202     strncpy(m_thisCommand,line_in, 1023);
203     m_thisCommand[1023] = '\0';
204     free (line_in);
205 #else    
206     // Read using fgets(3)
207     printf (C_PROMPT);
208     fflush(stdout);
209     if (!fgets(m_thisCommand, 1023, stdin))
210         return 0;
211 #endif
212     // Remove trailing whitespace
213     char *cp = m_thisCommand + strlen(m_thisCommand);
214     while (cp != m_thisCommand && strchr("\t \n", cp[-1]))
215         cp--;
216     *cp = '\0';
217     cp = m_thisCommand;
218     // Remove leading spaces...
219     while (strchr ("\t \n", *cp))
220         cp++;
221     // Save command if non-empty
222     if (*cp != '\0')
223         strcpy (m_lastCommand, cp);
224     return m_lastCommand;
225 }
226
227 int MyClient::interactive(Yaz_SocketManager *socketManager)
228 {
229     const char *cmd;
230     if (!m_interactive_flag)
231         return 0;
232     while ((cmd = getCommand()))
233     {
234         if (!processCommand(cmd))
235             break;
236     }
237     return 0;
238 }
239
240 int MyClient::args(Yaz_SocketManager *socketManager, int argc, char **argv)
241 {
242     char *host = 0;
243     char *proxy = 0;
244     char *arg;
245     char *prog = argv[0];
246     int ret;
247
248     while ((ret = options("p:v:q", argv, argc, &arg)) != -2)
249     {
250         switch (ret)
251         {
252         case 0:
253             if (host)
254             {
255                 usage(prog);
256                 return 1;
257             }
258             host = arg;
259             break;
260         case 'p':
261             if (proxy)
262             {
263                 usage(prog);
264                 return 1;
265             }
266             set_proxy(arg);
267             break;
268         case 'v':
269             log_init_level (log_mask_str(arg));
270             break;
271         case 'q':
272             m_interactive_flag = 0;
273             break;
274         default:
275             usage(prog);
276             return 1;
277         }
278     }
279     if (host)
280     {
281         client (host);
282         send_initRequest();
283         wait ();
284     }
285     return 0;
286 }
287
288 int main(int argc, char **argv)
289 {
290     Yaz_SocketManager mySocketManager;
291     Yaz_PDU_Assoc *some = new Yaz_PDU_Assoc(&mySocketManager, 0);
292
293     MyClient z(some, &mySocketManager);
294
295     if (z.args(&mySocketManager, argc, argv))
296         exit (1);
297     if (z.interactive(&mySocketManager))
298         exit (1);
299 }