C++ fixes.
[yaz-moved-to-github.git] / client / admin.c
1 /*
2  * $Log: admin.c,v $
3  * Revision 1.9  2001-02-21 13:46:53  adam
4  * C++ fixes.
5  *
6  * Revision 1.8  2000/04/17 14:21:38  adam
7  * WIN32 update.
8  *
9  * Revision 1.7  2000/04/05 07:39:54  adam
10  * Added shared library support (libtool).
11  *
12  * Revision 1.6  2000/03/20 19:06:25  adam
13  * Added Segment request for fronend server. Work on admin for client.
14  *
15  * Revision 1.5  2000/03/17 12:47:02  adam
16  * Minor changes to admin client.
17  *
18  * Revision 1.4  2000/03/16 13:55:49  ian
19  * Added commands for sending shutdown and startup admin requests via the admin ES.
20  *
21  * Revision 1.3  2000/03/14 15:23:17  ian
22  * Removed unwanted ifdef and include of zes-admin.h
23  *
24  * Revision 1.2  2000/03/14 14:06:04  ian
25  * Minor change to order of debugging output for send_apdu,
26  * fixed encoding of admin request.
27  *
28  * Revision 1.1  2000/03/14 09:27:07  ian
29  * Added code to enable sending of admin extended service requests
30  *
31  *
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <time.h>
37 #include <assert.h>
38
39 #ifdef WIN32
40
41 #else
42 #include <dirent.h>
43 #include <fnmatch.h>
44 #include <sys/stat.h>
45 #endif
46
47 #include <yaz/yaz-util.h>
48
49 #include <yaz/tcpip.h>
50 #ifdef USE_XTIMOSI
51 #include <yaz/xmosi.h>
52 #endif
53
54 #include <yaz/proto.h>
55 #include <yaz/marcdisp.h>
56 #include <yaz/diagbib1.h>
57
58 #include <yaz/pquery.h>
59
60 #ifdef ASN_COMPILED
61
62 /* Helper functions to get to various statics in the client */
63 ODR getODROutputStream();
64 void send_apdu(Z_APDU *a);
65
66 extern char *databaseNames[];
67 extern int num_databaseNames;
68
69 int sendAdminES(int type, char* param1)
70 {
71     ODR out = getODROutputStream();
72     char *dbname = odr_strdup (out, databaseNames[0]);
73
74     /* Type: 1=reindex, 2=truncate, 3=delete, 4=create, 5=import, 6=refresh, 7=commit */
75     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
76     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
77     Z_External *r;
78     int oid[OID_SIZE];
79     Z_ESAdminOriginPartToKeep  *toKeep;
80     Z_ESAdminOriginPartNotToKeep  *notToKeep;
81     oident update_oid;
82     printf ("Admin request\n");
83     fflush(stdout);
84
85     /* Set up the OID for the external */
86     update_oid.proto = PROTO_Z3950;
87     update_oid.oclass = CLASS_EXTSERV;
88     update_oid.value = VAL_ADMINSERVICE;
89
90     oid_ent_to_oid (&update_oid, oid);
91     req->packageType = odr_oiddup(out,oid);
92     req->packageName = "1.Extendedserveq";
93
94     /* Allocate the external */
95     r = req->taskSpecificParameters = (Z_External *) odr_malloc (out, sizeof(*r));
96     r->direct_reference = odr_oiddup(out,oid);
97     r->indirect_reference = 0;
98     r->descriptor = 0;
99     r->which = Z_External_ESAdmin;
100     r->u.adminService = (Z_Admin *) odr_malloc(out, sizeof(*r->u.adminService));
101     r->u.adminService->which = Z_Admin_esRequest;
102     r->u.adminService->u.esRequest = (Z_AdminEsRequest *) odr_malloc(out, sizeof(*r->u.adminService->u.esRequest));
103
104     toKeep = r->u.adminService->u.esRequest->toKeep = (Z_ESAdminOriginPartToKeep *) 
105                      odr_malloc(out, sizeof(*r->u.adminService->u.esRequest->toKeep));
106
107     toKeep->which=type;
108     toKeep->databaseName = dbname;
109     switch ( type )
110     {
111     case Z_ESAdminOriginPartToKeep_reIndex:
112         toKeep->u.reIndex=odr_nullval();
113         break;
114         
115     case Z_ESAdminOriginPartToKeep_truncate:
116         toKeep->u.truncate=odr_nullval();
117         break;
118     case Z_ESAdminOriginPartToKeep_drop:
119         toKeep->u.drop=odr_nullval();
120         break;
121     case Z_ESAdminOriginPartToKeep_create:
122         toKeep->u.create=odr_nullval();
123         break;
124     case Z_ESAdminOriginPartToKeep_import:
125         toKeep->u.import = (Z_ImportParameters*)odr_malloc(out, sizeof(*toKeep->u.import));
126         toKeep->u.import->recordType=param1;
127         /* Need to add additional setup of records here */
128         break;
129     case Z_ESAdminOriginPartToKeep_refresh:
130         toKeep->u.refresh=odr_nullval();
131         break;
132     case Z_ESAdminOriginPartToKeep_commit:
133         toKeep->u.commit=odr_nullval();
134         break;
135     case Z_ESAdminOriginPartToKeep_shutdown:
136         toKeep->u.commit=odr_nullval();
137         break;
138     case Z_ESAdminOriginPartToKeep_start:
139         toKeep->u.commit=odr_nullval();
140         break;
141     default:
142         /* Unknown admin service */
143         break;
144     }
145
146     notToKeep = r->u.adminService->u.esRequest->notToKeep =
147         (Z_ESAdminOriginPartNotToKeep *)
148         odr_malloc(out, sizeof(*r->u.adminService->u.esRequest->notToKeep));
149     notToKeep->which=Z_ESAdminOriginPartNotToKeep_recordsWillFollow;
150     notToKeep->u.recordsWillFollow=odr_nullval();
151     
152     send_apdu(apdu);
153     
154     return 0;
155 }
156
157 /* cmd_adm_reindex
158    Ask the specified database to fully reindex itself */
159 int cmd_adm_reindex(char* arg)
160 {
161     sendAdminES(Z_ESAdminOriginPartToKeep_reIndex, NULL);
162     return 2;
163 }
164
165 /* cmd_adm_truncate
166    Truncate the specified database, removing all records and index entries, but leaving 
167    the database & it's explain information intact ready for new records */
168 int cmd_adm_truncate(char* arg)
169 {
170     if ( arg )
171     {
172         sendAdminES(Z_ESAdminOriginPartToKeep_truncate, NULL);
173         return 2;
174     }
175     return 0;
176 }
177
178 /* cmd_adm_create
179    Create a new database */
180 int cmd_adm_create(char* arg)
181 {
182     if ( arg )
183     {
184         sendAdminES(Z_ESAdminOriginPartToKeep_create, NULL);
185         return 2;
186     }
187     return 0;
188 }
189
190 /* cmd_adm_drop
191    Drop (Delete) a database */
192 int cmd_adm_drop(char* arg)
193 {
194     if ( arg )
195     {
196         sendAdminES(Z_ESAdminOriginPartToKeep_drop, NULL);
197         return 2;
198     }
199     return 0;
200 }
201
202 /* cmd_adm_import <dbname> <rectype> <sourcefile>
203    Import the specified updated into the database
204    N.B. That in this case, the import may contain instructions to delete records as well as new or updates
205    to existing records */
206
207 #ifdef WIN32
208 int cmd_adm_import(char *arg)
209 {
210     printf ("not available on WIN32\n");
211     return 0;
212 }
213
214 #else
215
216 int cmd_adm_import(char *arg)
217 {
218     char type_str[20], dir_str[1024], pattern_str[1024];
219     char *cp;
220     char *sep = "/";
221     DIR *dir;
222     struct dirent *ent;
223     int chunk = 10;
224     Z_APDU *apdu = 0;
225     ODR out = getODROutputStream();
226
227     if (arg && sscanf (arg, "%19s %1023s %1023s", type_str,
228                        dir_str, pattern_str) != 3)
229         return 0;
230     if (num_databaseNames != 1)
231         return 0;
232     dir = opendir(dir_str);
233     if (!dir)
234         return 0;
235     
236     sendAdminES(Z_ESAdminOriginPartToKeep_import, type_str);
237
238     printf ("sent es request\n");
239     if ((cp=strrchr(dir_str, '/')) && cp[1] == 0)
240         sep="";
241         
242     while ((ent = readdir(dir)))
243     {
244         if (fnmatch (pattern_str, ent->d_name, 0) == 0)
245         {
246             char fname[1024];
247             struct stat status;
248             FILE *inf;
249                 
250             sprintf (fname, "%s%s%s", dir_str, sep, ent->d_name);
251             stat (fname, &status);
252
253             if (S_ISREG(status.st_mode) && (inf = fopen(fname, "r")))
254             {
255                 Z_Segment *segment;
256                 Z_NamePlusRecord *rec;
257                 Odr_oct *oct = (Odr_oct *) odr_malloc (out, sizeof(*oct));
258
259                 if (!apdu)
260                 {
261                     apdu = zget_APDU(out, Z_APDU_segmentRequest);
262                     segment = apdu->u.segmentRequest;
263                     segment->segmentRecords = (Z_NamePlusRecord **)
264                         odr_malloc (out, chunk * sizeof(*segment->segmentRecords));
265                 }
266                 rec = (Z_NamePlusRecord *) odr_malloc (out, sizeof(*rec));
267                 rec->databaseName = 0;
268                 rec->which = Z_NamePlusRecord_intermediateFragment;
269                 rec->u.intermediateFragment = (Z_FragmentSyntax *)
270                     odr_malloc (out, sizeof(*rec->u.intermediateFragment));
271                 rec->u.intermediateFragment->which =
272                     Z_FragmentSyntax_notExternallyTagged;
273                 rec->u.intermediateFragment->u.notExternallyTagged = oct;
274                 
275                 oct->len = oct->size = status.st_size;
276                 oct->buf = (unsigned char *) odr_malloc (out, oct->size);
277                 fread (oct->buf, 1, oct->size, inf);
278                 fclose (inf);
279                 
280                 segment->segmentRecords[segment->num_segmentRecords++] = rec;
281
282                 if (segment->num_segmentRecords == chunk)
283                 {
284                     send_apdu (apdu);
285                     apdu = 0;
286                 }
287             }   
288         }
289     }
290     if (apdu)
291         send_apdu(apdu);
292     apdu = zget_APDU(out, Z_APDU_segmentRequest);
293     send_apdu (apdu);
294     closedir(dir);
295     return 2;
296 }
297 #endif
298
299 int cmd_adm_import2(char* arg)
300 {
301    /* Buffer for reading chunks of data from import file */
302     char chunk_buffer[8192];
303     
304     if ( arg )
305     {
306         char rectype_buff[32];
307         char filename_buff[32];
308         FILE* pImportFile = NULL;
309
310         if (sscanf (arg, "%s %s", rectype_buff, filename_buff) != 3)
311         {
312             printf("Must specify database-name, record-type and filename for import\n");
313             return 0;
314         }
315
316         /* Attempt to open the file */
317
318         pImportFile = fopen(filename_buff,"r");
319
320         /* This chunk of code should move into client.c sometime soon for sending files via the update es */
321         /* This function will then refer to the standard client.c one for uploading a file using es update */
322         if ( pImportFile )
323         {
324             int iTotalWritten = 0;
325
326             /* We opened the import file without problems... So no we send the es request, ready to 
327                start sending fragments of the import file as segment messages */
328             sendAdminES(Z_ESAdminOriginPartToKeep_import, rectype_buff);
329
330             while ( ! feof(pImportFile ) )
331             {
332                 /* Read buffer_size bytes from the file */
333                 size_t num_items = fread((void*)chunk_buffer, 1, sizeof(chunk_buffer),  pImportFile);
334
335                 /* Write num_bytes of data to */
336
337                 if ( feof(pImportFile ) )
338                 {
339                     /* This is the last chunk... Write it as the last fragment */
340                     printf("Last segment of %d bytes\n", num_items);
341                 }
342                 else if ( iTotalWritten == 0 )
343                 {
344                     printf("First segment of %d bytes\n",num_items);
345                 }
346                 else
347                 {
348                     printf("Writing %d bytes\n", num_items);
349                 }
350
351                 iTotalWritten += num_items;
352             }
353         }
354         return 2;
355     }
356     return 0;
357 }
358
359 /* "Freshen" the specified database, by checking metadata records against the sources from which they were 
360    generated, and creating a new record if the source has been touched since the last extraction */
361 int cmd_adm_refresh(char* arg)
362 {
363     if ( arg )
364     {
365         sendAdminES(Z_ESAdminOriginPartToKeep_refresh, NULL);
366         return 2;
367     }
368     return 0;
369 }
370
371 /* cmd_adm_commit 
372    Make imported records a permenant & visible to the live system */
373 int cmd_adm_commit(char* arg)
374 {
375     sendAdminES(Z_ESAdminOriginPartToKeep_commit, NULL);
376     return 2;
377 }
378
379 int cmd_adm_shutdown(char* arg)
380 {
381     sendAdminES(Z_ESAdminOriginPartToKeep_shutdown, NULL);
382     return 2;
383 }
384
385 int cmd_adm_startup(char* arg)
386 {
387     sendAdminES(Z_ESAdminOriginPartToKeep_start, NULL);
388     return 2;
389 }
390 #endif