Remove all optional compile flags from dtwm that are not referenced anywhere, and...
[oweals/cde.git] / cde / lib / DtSearch / dtoe.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *   COMPONENT_NAME: austext
25  *
26  *   FUNCTIONS: Opera_Engine
27  *              alarm_signal_handler
28  *              expired
29  *              no_keytypes
30  *              oe_unblob
31  *              oe_write_audit_rec
32  *              request_str
33  *              retncode_str
34  *              save_query
35  *
36  *   ORIGINS: 27
37  *
38  *
39  *   (C) COPYRIGHT International Business Machines Corp. 1991,1996
40  *   All Rights Reserved
41  *   Licensed Materials - Property of IBM
42  *   US Government Users Restricted Rights - Use, duplication or
43  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
44  */
45 /******************************* DTOE.C ********************************
46  * $XConsortium: dtoe.c /main/6 1996/11/25 18:52:51 drk $
47  * Sept 1991.
48  * Universal Opera Engine code.
49  * Additional functions in modules named OE...
50  * See comments in OE.H for Opera_Engine() function descriptions.
51  * References to 'socblk' have all been replaced by usrblk,
52  * which is now the universal data structure.
53  *
54  * $Log$
55  * Revision 2.8  1996/03/20  19:25:31  miker
56  * Use new hilite_cleartext() function call.
57  *
58  * Revision 2.7  1996/03/13  22:51:39  miker
59  * Changed char to UCHAR several places.
60  * Revision 2.6  1996/03/05  19:20:58  miker
61  * Replaced vewords with boolyac, boolpars, and boolsrch.
62  * oe_unblob no longer converts to uppercase.
63  * Revision 2.5  1996/02/01  17:15:18  miker
64  * 2.1.11:  Changes to support parsers using readchar cofunctions.
65  * Changed hiliting calls to hilite_cleartext.
66  * Obsoleted OE_FINDSTR_REC, OE_DITTO2KWIC, OE_FINDSTR_HITL.
67  * Revision 2.4  1995/12/27  16:47:12  miker
68  * Prolog update.
69  * Revision 2.3  1995/10/24  22:31:32  miker
70  * Renamed from oe.c.  Added prolog.
71  * Log: oe.c,v
72  * Revision 2.2  1995/10/03  21:44:24  miker
73  * Deleted unsigned attrib from misc variables for portability.
74  * Revision 2.1  1995/09/22  21:29:45  miker
75  * Freeze DtSearch 0.1, AusText 2.1.8
76  * Revision 1.19  1995/09/05  18:49:45  miker
77  * Changed all socblk refs to usrblk.  Obsoleted several globals.
78  * Conflated all msglists to one ausapi_msglist.  Numerous name changes.
79  * Added DTSEARCH define.  Remove password processing.
80  * Made usrblk a universal global.  ...All for DtSearch.
81  * Revision 1.18  1995/07/19  21:02:59  miker
82  * 2.1.6c: Removed OE_mail_feature and OE_print_server.
83  * Revision 1.17  1995/06/22  20:49:33  miker
84  * 2.1.6: Additional debugging messages.
85  * Revision 1.16  1995/05/30  19:20:51  miker
86  * Print a little more of msglist when debugging engine return.
87  */
88 #include "SearchE.h"
89 #include <ctype.h>
90 #include <string.h>
91 #include <errno.h>
92 #include <signal.h>
93 #include <sys/stat.h>
94 #include <stdlib.h>
95
96 #define PROGNAME        "DTOE"
97 #define MAX_LASTQRY     64
98 #define QRYBUFSZ        1024
99 #define MS_misc         1
100 #define MS_oe           10
101 /*******#define DUMP_HITWORDS*******/
102
103 typedef struct {
104     int             num;
105     char           *str;
106 }               NUMSTR;
107
108 int  boolean_parse (void);
109 void boolean_search (void);
110 void ve_delete (void);
111
112 /*------------------ OPERA ENGINE GLOBALS --------------------
113  * Default values set by init_globals() in oeinit.c
114  * (Some values preinitialized here by compiler because 
115  * they may be used before the first call to init_globals()).
116  * Most can be overridden by site configuration file.
117  * Obviously any changes here should be reflected in init_globals().
118  * Other OE_... globals are located in loadocf.c
119  */
120 extern int      debugging_jpn;
121 extern int      debugging_teskey;
122 char           *global_memory_ptr = NULL;       /* shared mem, dynam
123                                                  * defrag */
124 int             shm_id = 0;     /* shared mem, dynam defrag */
125
126 int             OE_bmhtab_strlen[DtSrMAX_STEMCOUNT] = { 0 };
127 size_t          OE_bmhtables[DtSrMAX_STEMCOUNT][MAX_BMHTAB] = { { 0 } };
128 int             OE_dbn = 0;     /* dynamic */
129 int             OE_enable_markdel = 0;
130 int             OE_enable_usernotes = 0;
131 int             OE_fastdecode = 0;
132 char           *OE_fileio = NULL;
133 long            OE_flags = 0L;
134 long            OE_objsize = 0L;
135 char           *OE_prodname = PRODNAME; /* reset only in main() */
136 float           OE_prox_factor = 0.0;
137 int             OE_search_type = 0;
138 char           *OE_sitecnfg_fname = NULL;
139 time_t          OE_sitecnfg_mtime = 0L; /* reset only in oeinitialize() */
140 int             OE_uppercase_keys = 0;
141 long            OE_words_hitlimit = 0L;
142
143 static time_t   my_expiration = 0L;
144 time_t         *OE_expiration = &my_expiration;
145
146 char           *OEF_audit = NULL;
147 char           *OEF_discard = NULL;
148 char           *OEF_news = NULL;
149 char           *OEF_notesnot = NULL;
150 char           *OEF_notessem = NULL;
151 char           *OEF_readme = NULL;
152
153
154 /*------------ OTHER GLOBALS -----------*/
155 SAVEUSR         saveusr = { 0 };
156
157
158 /****************************************/
159 /*                                      */
160 /*              expired                 */
161 /*                                      */
162 /****************************************/
163 /* This function permanently disables opera 
164  * if the license to opera has expired.
165  */
166 static void     expired (char *sprintbuf)
167 {
168     sprintf (sprintbuf, catgets (dtsearch_catd, MS_oe, 71,
169         PROGNAME "71 %s has expired."),
170         OE_prodname);
171     DtSearchAddMessage (sprintbuf);
172     OE_flags |= OE_PERMERR;
173     usrblk.retncode = OE_ABORT;
174     return;
175 }  /* expired() */
176
177
178 /************************************************/
179 /*                                              */
180 /*            alarm_signal_handler              */
181 /*                                              */
182 /************************************************/
183 /* Interrupt handler for SIGALRM */
184 static void     alarm_signal_handler (int sig)
185 {
186     fprintf (aa_stderr, PROGNAME "32 "
187         "%s %s shutdown due to excessive user idle time.\n",
188         nowstring (NULL), aa_argv0);
189     DtSearchExit (100 + sig);
190 }  /* alarm_signal_handler() */
191
192
193 /****************************************/
194 /*                                      */
195 /*               oe_unblob              */
196 /*                                      */
197 /****************************************/
198 /* Converts a list of compressed text blob records
199  * straight out of vista into a single string of clear text.
200  * input = OE_objsize, dblk.hufid, passed bloblist (freed after use!).
201  * output = usrblk.cleartext, usrblk.clearlen.
202  * Returns OE_OK if all goes well, else returns other appropriate retncode.
203  */
204 int     oe_unblob (LLIST *bloblist)
205 {
206     UCHAR       *targ, *src, *stoploc;
207     short       blobclearlen;
208     LLIST       *lptr, *nextlptr;
209     long        mallocsz;
210     struct or_blobrec
211                 *bptr;
212
213     /*  Free previous cleartext, if any, and allocate new buffer */
214     if (OE_objsize < 512)
215         mallocsz = 512L;
216     else
217         mallocsz = OE_objsize + 4L;
218     if (usrblk.cleartext != NULL)
219         free (usrblk.cleartext);
220     usrblk.cleartext = austext_malloc (mallocsz, PROGNAME "188", NULL);
221     usrblk.clearlen = OE_objsize;
222
223     /* Uncompress/decipher bloblist into cleartext,
224      * freeing the blobs as we go.
225      */
226     targ = (UCHAR *) usrblk.cleartext;
227     stoploc = targ + OE_objsize;
228     lptr = bloblist;
229     while (lptr != NULL) {
230         /* Setup ptrs and counters for decoding */
231         bptr = (struct or_blobrec *) lptr->data;
232         src = (UCHAR *) bptr->or_blob;
233         blobclearlen = bptr->or_bloblen;  /* len of cleartext in curr blob */
234         if (targ + blobclearlen > stoploc) {
235             DtSearchAddMessage (PROGNAME "242 Logical Error in database. "
236                 "Object larger than stored size.");
237             free (usrblk.cleartext);
238             usrblk.clearlen = 0;
239             usrblk.retncode = OE_ABORT;
240             OE_flags |= OE_PERMERR;
241             return OE_ABORT;
242         }
243
244         /* Decode into clear text buffer */
245         hc_decode (src, targ, blobclearlen, usrblk.dblk->dbrec.or_hufid);
246
247         targ += blobclearlen;
248
249         /* free current blob, advance to next blob */
250         nextlptr = lptr->link;  /* temp save next blob addr */
251         free (lptr);
252         lptr = nextlptr;
253     }
254     *targ = 0;
255
256     if (usrblk.debug & USRDBG_RETRVL)
257         fprintf (aa_stderr, PROGNAME "256 "
258             "oe_unblob: actual decompressed length = %ld.\n",
259             (long) (targ - (UCHAR *) usrblk.cleartext));
260     return OE_OK;
261 }  /* oe_unblob() */
262
263
264 /************************************************/
265 /*                                              */
266 /*                save_query                    */
267 /*                                              */
268 /************************************************/
269 /* If AUDIT switch is turned on, saves query and start_time in saveusr 
270  * for later printing when search process has completed.
271  */
272 static void     save_query (char *prefix, time_t start_time)
273 {
274     char           *src, *targ, *end;
275
276     if (saveusr.lastqry != NULL)
277         free (saveusr.lastqry);
278     saveusr.lastqry = austext_malloc (MAX_LASTQRY, PROGNAME "500", NULL);
279
280     /* First copy prefix and "=" */
281     targ = saveusr.lastqry;
282     src = prefix;
283     while (*src != 0)
284         *targ++ = *src++;
285     *targ++ = '=';
286
287     /* Copy query after '=', replacing any ctrl chars
288      * with a displayable funny character (tilde ~).
289      */
290     if (usrblk.query == NULL)
291         strcpy (targ, catgets (dtsearch_catd, MS_misc, 1, "<null>"));
292     else {
293         end = saveusr.lastqry + MAX_LASTQRY - 2;
294         src = usrblk.query;
295         while (*src != 0 && targ < end) {
296             *targ = *src++;
297             if (*targ < 32)
298                 *targ = '~';
299             targ++;
300         }
301         *targ = 0;
302     }
303     saveusr.start_time = start_time;
304     return;
305 }  /* save_query() */
306
307
308 /************************************************/
309 /*                                              */
310 /*              oe_write_audit_rec              */
311 /*                                              */
312 /************************************************/
313 /* Writes out audit data after uninterrupted completion of a search.
314  * Caller checks if AUDIT flag is on.
315  * Argument is number of hits (may or may not = dittocount).
316  * By convention, numhits = -1 means search was canceled by user,
317  * numhits = -2 means system canceled search.
318  * Requires various saveusr and usrblk fields to be correct.
319  */
320 void            oe_write_audit_rec (long numhits)
321 {
322     char            sprintbuf[1024];
323     time_t          now_gmt;
324     FILE           *stream;
325
326     if ((stream = fopen (OEF_audit, "a ")) == NULL)
327         /* the blank in "a " works around old aix bug */
328     {
329         sprintf (sprintbuf, catgets (dtsearch_catd, MS_misc, 1596,
330                 PROGNAME "1596 Cannot open audit file %s: %s"),
331             OEF_audit, strerror (errno));
332         DtSearchAddMessage (sprintbuf);
333         OE_flags &= ~OE_AUDIT;  /* don't try to audit anything else */
334     }
335     else {
336         time (&now_gmt);
337         fprintf (stream, AUDIT_FORMAT "%s\n",
338             usrblk.userid,
339             nowstring (&now_gmt),
340             now_gmt - saveusr.start_time,       /* elapsed search time */
341             usrblk.dblk->name,
342             numhits,
343             (saveusr.lastqry == NULL) ? \
344             catgets (dtsearch_catd, MS_misc, 1, "<null>") : saveusr.lastqry);
345         if (saveusr.lastqry != NULL) {
346             free (saveusr.lastqry);
347             saveusr.lastqry = NULL;
348         }
349         fclose (stream);
350     }
351     return;
352 }  /* oe_write_audit_rec() */
353
354
355 /************************************************/
356 /*                                              */
357 /*                 no_keytypes                  */
358 /*                                              */
359 /************************************************/
360 /* Returns FALSE if any keytype in usrblk.dblk is_selected.
361  * Otherwise appends an error msg, sets usrblk.retncode
362  * to OE_BAD_QUERY, and returns TRUE.
363  */
364 static int      no_keytypes (void)
365 {
366     int             i = usrblk.dblk->ktcount;
367     char            sprintbuf[256];
368
369     DtSrKeytype    *keytypes = usrblk.dblk->keytypes;
370     while (--i >= 0)
371         if (keytypes[i].is_selected)
372             return FALSE;
373     sprintf (sprintbuf, catgets (dtsearch_catd, MS_oe, 440,
374             PROGNAME "440 No record keytypes were selected in database '%s'."),
375         usrblk.dblk->label);
376     DtSearchAddMessage (sprintbuf);
377     usrblk.retncode = OE_BAD_QUERY;
378     return TRUE;
379 }  /* no_keytypes() */
380
381
382 /************************************************/
383 /*                                              */
384 /*                request_str                   */
385 /*                                              */
386 /************************************************/
387 /* Returns string identifier for OE_... request numbers for debugging */
388 static char    *request_str (int reqnum)
389 {
390     static NUMSTR       numstr[] = {
391         {OE_INITIALIZE,         "INITIALIZE"},          /*  1 */
392         {OE_TEXT2FZKEY,         "TEXT2FZKEY"},          /*  2 */
393         {OE_SRCH_FZKEY,         "SRCH_FZKEY"},          /*  3 */
394         {OE_SRCH_STEMS,         "SRCH_STEMS"},          /*  4 */
395         {OE_SRCH_WORDS,         "SRCH_WORDS"},          /*  5 */
396         {OE_STOP_SRCH,          "STOP_SRCH"},           /*  6 */
397         {OE_APPEND_NOTES,       "APPEND_NOTES"},        /*  7 */
398         {OE_GETREC,             "GETREC"},              /*  8 */
399         {OE_GETREC_STEMS,       "GETREC_STEMS"},        /*  9 */
400         {OE_GETREC_WORDS,       "GETREC_WORDS"},        /* 10 */
401         {OE_NEXT_DBA,           "NEXT_DBA"},            /* 11 */
402         {OE_PREV_DBA,           "PREV_DBA"},            /* 12 */
403         {OE_RECKEY2DBA,         "RECKEY2DBA"},          /* 13 */
404         {OE_MARK_DELETION,      "MARK_DELETION"},       /* 14 */
405         {OE_GETREC_DIC,         "GETREC_DIC"},          /* 15 */
406         {OE_DITTO2KWIC,         "DITTO2KWIC"},          /* 16 */
407         {OE_VALIDATE_PWD,       "VALIDATE_PWD"},        /* 17 */
408         {OE_CHANGE_PWD,         "CHANGE_PWD"},          /* 18 */
409         {OE_DELETE_RECID,       "DELETE_RECID"},        /* 19 */
410         {OE_DELETE_BATCH,       "DELETE_BATCH"},        /* 20 */
411         {OE_ASSIST,             "ASSIST"},              /* 21 */
412         {OE_FINDSTR_REC,        "FINDSTR_REC"},         /* 22 */
413         {OE_FINDSTR_HITL,       "FINDSTR_HITL"},        /* 23 */
414         {OE_SRCH_STATISTICAL,   "SRCH_STATISTICAL"},    /* 24 */
415         {OE_HILITE_STEMS,       "HILITE_STEMS"},        /* 25 */
416         {OE_GET_EXPIRE,         "GET_EXPIRE"},          /* 26 */
417         {OE_KILL,               "KILL"},                /* 9997 */
418         {OE_PING,               "PING"},                /* 9998 */
419         {OE_SHUTDOWN,           "SHUTDOWN"},            /* 9999 */
420         {0,                     "<unknown>"}
421         };
422     NUMSTR              *ptr = numstr;
423
424     while (reqnum != ptr->num  &&  ptr->num != 0)
425         ptr++;
426     return ptr->str;
427 } /* request_str() */
428
429
430 /************************************************/
431 /*                                              */
432 /*                retncode_str                  */
433 /*                                              */
434 /************************************************/
435 /* Returns string identifier for OE_... retncode numbers for debugging */
436 char    *retncode_str (int num)
437 {
438     static char         buf [16];
439     static NUMSTR       numstr[] = {
440         {OE_OK,         "OE_OK"},               /*  1 */
441         {OE_REINIT,     "OE_REINIT"},           /*  2 */
442         {OE_SEARCHING,  "OE_SEARCHING"},        /*  3 */
443         {OE_BAD_DBLK,   "OE_BAD_DBLK"},         /*  4 */
444         {OE_BAD_REQUEST,"OE_BAD_REQUEST"},      /*  5 */
445         {OE_BAD_QUERY,  "OE_BAD_QUERY"},        /*  6 */
446         {OE_NOTAVAIL,   "OE_NOTAVAIL"},         /*  7 */
447         {OE_TIMEOUT,    "OE_TIMEOUT"},          /*  8 */
448         {OE_WRAPPED,    "OE_WRAPPED"},          /*  9 */
449         {OE_SYSTEM_STOP,"OE_SYSTEM_STOP"},      /*  10 */
450         {OE_BAD_PASSWD, "OE_BAD_PASSWD"},       /*  11 */
451         {OE_BAD_HITLIST,"OE_BAD_HITLIST"},      /*  12 */
452         {OE_DISABLED,   "OE_DISABLED"},         /*  13 */
453         {OE_USER_STOP,  "OE_USER_STOP"},        /*  14 */
454         {OE_BAD_COMM,   "OE_BAD_COMM"},         /*  15 */
455         {OE_NOOP,       "OE_NOOP"},             /*  888 */
456         {OE_ABORT,      "OE_ABORT"},            /*  999 */
457         {0,             buf}
458         };
459     NUMSTR              *ptr = numstr;
460
461     while (num != ptr->num  &&  ptr->num != 0)
462         ptr++;
463     if (ptr->num == 0)
464         sprintf (buf, "%d(?)", num);
465     return ptr->str;
466 } /* retncode_str() */
467
468
469 /************************************************/
470 /*                                              */
471 /*                Opera_Engine                  */
472 /*                                              */
473 /************************************************/
474 void            Opera_Engine (void)
475 {
476     int         i;
477     char        sprintbuf [1024];
478     LLIST       *bloblist;
479     DBLK        *db;
480     DB_ADDR     dba;
481     static time_t
482                 start_time = 0L;
483
484     extern int      database_has_changed (void);
485
486     time (&start_time); /* time that current call began */
487
488     if (usrblk.debug != 0L) {
489         if ((usrblk.debug & USRDBG_PARSE) != 0) {
490             debugging_jpn = TRUE;
491             debugging_teskey = TRUE;
492         }
493         /*
494          * Place strings for 3 interesting time stamps at sprintbuf
495          * +0, +100, and +200. 
496          */
497         strcpy (sprintbuf, nowstring (&start_time));
498         if (*OE_expiration != 0L)
499             strcpy (sprintbuf + 100, nowstring (OE_expiration));
500         else
501             strcpy (sprintbuf + 100, "0");
502         if (OE_sitecnfg_mtime != 0)
503             strcpy (sprintbuf + 200, nowstring (&OE_sitecnfg_mtime));
504         else
505             strcpy (sprintbuf + 200, "0");
506         fprintf (aa_stderr,
507             "\n" PROGNAME "444  Opera_Engine Request %d (%s) at %s.\n"
508             "  user='%s', usrblk.flags=%ld(x%04lx), usrblk.debug=%ld(x%04lx).\n"
509             "  OE_flags=%ld(x%04lx), exp=%s, sitecnfg=%s.\n"
510             ,usrblk.request, request_str (usrblk.request), sprintbuf
511             ,usrblk.userid, usrblk.flags, usrblk.flags
512             ,usrblk.debug, usrblk.debug
513             ,OE_flags, OE_flags, sprintbuf + 100, sprintbuf + 200
514             );
515         i = 0;
516         for (db = usrblk.dblist; db != NULL; db = db->link) {
517             if (db == usrblk.dblk)
518                 break;
519             i++;
520         }
521         if (db == NULL)
522             fprintf (aa_stderr, "  dblk is %s\n",
523                 (i) ? "INVALID!" : "null.");
524         else
525             fprintf (aa_stderr, "  dblk #%d: name='%s', vistano=%d.\n"
526                 ,i, usrblk.dblk->name, usrblk.dblk->vistano
527                 );
528         fflush (aa_stderr);
529     }
530
531     /* Check if this copy of opera has expired.
532      * If *OE_expiration == 0, expiration checking disabled.
533      * If current time < expiration time, permit request.
534      * Otherwise disable this and all further requests. 
535      */
536
537     if (*OE_expiration != 0L)
538         if (start_time > *OE_expiration)
539             expired (sprintbuf);
540
541     if (OE_flags & OE_PERMERR) {
542         sprintf (sprintbuf, catgets (dtsearch_catd, MS_oe, 490,
543                 PROGNAME "490 %s Engine permanently disabled."), OE_prodname);
544         DtSearchAddMessage (sprintbuf);
545         usrblk.retncode = OE_ABORT;
546         goto ENGINE_RETURN;
547     }
548
549     /* Ensure that the first call is always an OE_INITIALIZE call */
550     if ((usrblk.request != OE_INITIALIZE) && !(OE_flags & OE_INITOK)) {
551         DtSearchAddMessage (catgets (dtsearch_catd, MS_oe, 523,
552                 PROGNAME "523 Request Denied: First request must "
553                 "be Engine Initialization."));
554         usrblk.retncode = OE_NOOP;
555         goto ENGINE_RETURN;
556     }
557
558     /* Verify that none of the databases has changed since the last call.  */
559     if (database_has_changed ())
560         goto ENGINE_RETURN;
561
562     /* Make usrblk ready.  Basically ensure client side
563      * has not destroyed usrblk.  Set OE_dbn to match user's dblk.
564      * The make-ready activity is not called for OE_INITIALIZE
565      * because the site's config file has not yet been called
566      * to create the OE's dblks.
567      */
568     if (usrblk.request != OE_INITIALIZE) {
569         /* Set OE_dbn to match selected dblk */
570         for (   db = usrblk.dblist,  OE_dbn = 0;
571                 db != NULL;
572                 db = db->link,  OE_dbn++)
573             if (strcmp (usrblk.dblk->name, db->name) == 0)
574                 break;
575         if (db == NULL) {
576             sprintf (sprintbuf, catgets (dtsearch_catd, MS_oe, 48,
577                     PROGNAME "48 Request Aborted: "
578                     "'%s' database not available at this site."),
579                 usrblk.dblk->name);
580             DtSearchAddMessage (sprintbuf);
581             usrblk.retncode = OE_ABORT;
582             OE_flags |= OE_PERMERR;
583             goto ENGINE_RETURN;
584         }
585         /* Override user switches if required by the engine */
586         if ((OE_flags & OE_NO_ITERATE) != 0)
587             usrblk.flags |= USR_NO_ITERATE;
588     }
589
590 /*----------------- BIG SWITCH ON REQUEST CODE ------------------*/
591     switch (usrblk.request) {
592         case OE_SRCH_STEMS:
593         case OE_SRCH_WORDS:
594             /*
595              * Builds dittolist from query of stems/words +
596              * booleans. Swap stoplists to fool search functions. 
597              */
598             if (no_keytypes ())
599                 break;
600             usrblk.search_type =
601                 (usrblk.request == OE_SRCH_WORDS)? 'W' : 'S';
602             if (OE_flags & OE_AUDIT)
603                 save_query ("WORDS", start_time);
604             /****ve_word_search ();*****/
605             if (!boolean_parse()) {
606                 usrblk.retncode = OE_BAD_QUERY;
607                 break;
608             }
609             boolean_search();
610             if (usrblk.debug & USRDBG_SRCHCMPL)
611                 print_stems (usrblk.stemcount, usrblk.stems, PROGNAME"637");
612             if (usrblk.debug & (USRDBG_SRCHCMPL | USRDBG_HITLIST))
613                 print_dittolist (usrblk.dittolist, PROGNAME "657");
614             break;
615
616         case OE_SRCH_STATISTICAL:
617             /*
618              * Builds dittolist from query string of natural
619              * language text whose words cause statistical doc
620              * retrieval. 
621              */
622             if (no_keytypes ())
623                 break;
624             if (OE_flags & OE_AUDIT)
625                 save_query ("STAT", start_time);
626             ve_statistical ();
627             if (usrblk.debug & USRDBG_SRCHCMPL)
628                 print_stems (usrblk.stemcount, usrblk.stems,
629                     PROGNAME"770 SRCH_STATISTICAL:");
630             if (usrblk.debug & (USRDBG_SRCHCMPL | USRDBG_HITLIST))
631                 print_dittolist (usrblk.dittolist, PROGNAME "772");
632             break;
633
634         case OE_HILITE_STEMS:
635             if (usrblk.debug & (USRDBG_RETRVL | USRDBG_HILITE)) {
636                 fprintf (aa_stderr, PROGNAME "819 HILITE_STEMS: "
637                     "srchtyp=%c clrln=%ld clrtxt='%.30s'\n",
638                     usrblk.search_type, usrblk.clearlen,
639                     NULLORSTR (usrblk.cleartext));
640                 print_stems (usrblk.stemcount, usrblk.stems, " ");
641             }
642             if (usrblk.cleartext == NULL  ||  usrblk.clearlen <= 0) {
643 NO_TEXT:
644                 DtSearchAddMessage (
645                     PROGNAME "839 Client Error: No Text to highlight.");
646                 usrblk.retncode = OE_BAD_QUERY;
647                 break;
648             }
649             if (usrblk.cleartext[0] == '\0')
650                 goto NO_TEXT;
651             if (usrblk.stemcount <= 0) {
652                 DtSearchAddMessage (PROGNAME "846 Client Error: "
653                     "Cannot highlight words, stemcount is zero.");
654                 usrblk.retncode = OE_BAD_QUERY;
655                 break;
656             }
657             /* Subswitch: depending on request, load hitwords array */
658             switch (usrblk.search_type) {
659                 case 'W':
660                     i = 'W';
661                     break;
662                 case 'S':
663                 case 'P':
664                     i = 'S';
665                     break;
666                 default:
667                     i = 0;
668                     DtSearchAddMessage (
669                         PROGNAME "708 Word Highlighting is not available "
670                         "for semantic searches.");
671                     usrblk.retncode = OE_BAD_QUERY;
672                     break;
673             }
674             if (!i)
675                 break;
676             hilite_cleartext (i, (char *) usrblk.stems, usrblk.stemcount);
677             if (OE_flags & OE_PERMERR)
678                 usrblk.retncode = OE_ABORT;
679             else
680                 usrblk.retncode = OE_OK;
681             if (usrblk.debug & USRDBG_RETRVL) {
682                 fprintf (aa_stderr,
683                     PROGNAME "820 HILITE_STEMS: hitwcount=%ld\n",
684                     usrblk.hitwcount);
685             }
686             break;      /* end OE_HILITE_STEMS */
687
688
689         case OE_STOP_SRCH:
690             /* interrupts long, ongoing search of database */
691             usrblk.flags |= USR_STOPSRCH;
692             usrblk.retncode = OE_OK;
693             break;
694
695
696         case OE_GETREC:
697         case OE_GETREC_WORDS:
698         case OE_GETREC_STEMS:
699         case OE_GETREC_DIC:
700             /*
701              * Retrieve database record, text blobs, notes, etc.
702              * Note that ve_getrec_dba() may return OE_OK even if
703              * there are no blobs.  That will happen when it can
704              * return everything else about the record, but by
705              * design the text itself is not stored in the
706              * repository. In other words, no blobs is not an error
707              * so check if blobs were returned and adjust retncode
708              * accordingly. 
709              */
710             usrblk.retncode = ve_getrec_dba (&bloblist);
711             if (usrblk.retncode != OE_OK)
712                 break;
713             /*
714              * If no text blobs, ensure cleartext and hitwords
715              * array are empty (which will cause OE_NOTAVAIL return
716              * below). Don't create a "no text" msg because many
717              * clients will want to retrieve the record text
718              * locally and they won't want an "error" msg
719              * cluttering up the msglist. 
720              */
721             if (bloblist == NULL) {
722                 usrblk.clearlen = 0;
723                 if (usrblk.cleartext != NULL) {
724                     free (usrblk.cleartext);
725                     usrblk.cleartext = NULL;
726                 }
727                 clear_hitwords ();
728             }
729             /*
730              * Otherwise if text blobs do exist, convert them into
731              * clear text and a hitwords array for hiliting. 
732              */
733             else {
734                 usrblk.retncode = oe_unblob (bloblist);
735                 if (usrblk.retncode != OE_OK)
736                     break;
737
738                 /* Subswitch: depending on request, load hitwords array */
739                 switch (usrblk.request) {
740                     case OE_GETREC_WORDS:
741                         hilite_cleartext ('W',
742                             (char*) usrblk.stems, usrblk.stemcount);
743                         break;
744
745                     case OE_GETREC_STEMS:
746                         hilite_cleartext ('S',
747                             (char*) usrblk.stems, usrblk.stemcount);
748                         break;
749
750                     case OE_GETREC_DIC:
751                         DtSearchAddMessage (PROGNAME "783 "
752                             "Dictionary word hiliting function "
753                             "is no longer supported.");
754                         clear_hitwords ();
755                         break;
756
757                     case OE_GETREC:
758                     default:
759                         clear_hitwords ();      /* ensure no hiliting */
760                 }       /* end hitwords subswitch */
761
762 #ifdef DUMP_HITWORDS    /* dump the stems and hitwords arrays */
763                 print_stems (usrblk.stemcount, usrblk.stems, "\nSTEMS:");
764                 fprintf (aa_stderr, "HITWORDS: hitwcount = %d\n",
765                     usrblk.hitwcount);
766                 for (i = 0; i < usrblk.hitwcount; i++)
767                     fprintf (aa_stderr, "offset = %4ld, len=%2d, '%.10s...'\n",
768                         usrblk.hitwords[i].offset,
769                         usrblk.hitwords[i].length,
770                         usrblk.cleartext + usrblk.hitwords[i].offset);
771 #endif
772             }   /* end if where blobs exist */
773
774             if (OE_flags & OE_PERMERR)
775                 usrblk.retncode = OE_ABORT;
776             else {
777                 usrblk.retncode = ((usrblk.clearlen) ? OE_OK : OE_NOTAVAIL);
778                 if (usrblk.debug & USRDBG_RETRVL)
779                     print_usrblk_record (PROGNAME "957 final: ");
780             }
781             break;      /* end cases OE_GETREC... */
782
783
784         case OE_NEXT_DBA:
785             /*
786              * increments dba address field (not associated with
787              * hitlist) 
788              */
789             ve_browse_dba (+1);
790             break;
791
792         case OE_PREV_DBA:
793             /*
794              * decrements dba address field (not associated with
795              * hitlist) 
796              */
797             ve_browse_dba (-1);
798             break;
799
800         case OE_APPEND_NOTES:
801             /* appends user notes to record at dba */
802             usrblk.retncode = ve_append_notes ();
803             break;
804
805         case OE_RECKEY2DBA:
806             /* converts vista record key to database address */
807             usrblk.dba = ve_reckey2dba ();
808             if ((usrblk.debug & USRDBG_DELETE) != 0L)
809                 fprintf (aa_stderr, PROGNAME "1089 RECKEY2DBA: "
810                     "retncode=%d, reckey='%s' ->\tdba=%ld:%ld\n",
811                     usrblk.retncode, usrblk.query,
812                      (long) ((usrblk.dba) >> 24), (long) ((usrblk.dba) & 0xffffff));
813             break;
814
815         case OE_DELETE_RECID:
816             /*
817              * First converts recid to a db address.  Then deletes
818              * entire record: blobs, notes, and words. Presumes
819              * only 2 retncodes from reckey2dba are OK and WRAPPED.
820              * (bad presumption). 
821              */
822             dba = ve_reckey2dba ();
823             if (usrblk.retncode != OE_OK) {
824                 usrblk.retncode = OE_NOTAVAIL;
825                 break;
826             }
827             usrblk.dba = dba;
828             usrblk.dbatab = &usrblk.dba;
829             usrblk.dbacount = 1;
830             ve_delete ();
831             break;
832
833         case OE_DELETE_BATCH:
834             /* deletes all records in a table of dba's */
835             ve_delete ();
836             break;
837
838         case OE_INITIALIZE:
839             /*
840              * first call from UI.  returns info used to build
841              * users screen 
842              */
843             oe_initialize ();
844             break;
845
846         case OE_GET_EXPIRE:
847             usrblk.dba = *OE_expiration;
848             usrblk.retncode = OE_OK;
849             break;
850
851         case OE_PING:
852             /* Null function.  Just does REINIT checks etc. */
853             usrblk.retncode = OE_OK;
854             break;
855
856         case OE_SHUTDOWN:
857         case OE_KILL:
858         case OE_VALIDATE_PWD:
859         case OE_CHANGE_PWD:
860             /* These functions are obsolete and harmless */
861             usrblk.retncode = OE_OK;
862             break;
863
864         case OE_FINDSTR_REC:
865         case OE_FINDSTR_HITL:
866         case OE_DITTO2KWIC:
867             /* These functions are just obsolete */
868             sprintf (sprintbuf,
869                 PROGNAME"1027: User Interface Error.  "
870                 "%d is obsolete request code.\n",
871                 usrblk.request);
872             DtSearchAddMessage (sprintbuf);
873             usrblk.retncode = OE_BAD_REQUEST;
874             break;
875
876         default:
877             sprintf (sprintbuf, catgets (dtsearch_catd, MS_oe, 367,
878                     PROGNAME "367: User Interface Error.  "
879                     "%d is invalid request code.\n"),
880                 usrblk.request);
881             DtSearchAddMessage (sprintbuf);
882             usrblk.retncode = OE_BAD_REQUEST;
883             break;
884
885     }   /* end switch */
886
887 ENGINE_RETURN:
888     if (usrblk.debug != 0L) {
889         if (!DtSearchHasMessages())
890             fprintf (aa_stderr, PROGNAME"998 Msglist is empty.\n");
891         else {
892             fprintf (aa_stderr,
893                 "mmmmmmmmmm Msglist mmmmmmmmm\n%s\n"
894                 "mmmmmmmmmmmmmmmmmmmmmmmmmmmm\n",
895                 DtSearchGetMessages());
896         }
897         fprintf (aa_stderr, PROGNAME "999 usrblk.retncode = %d (%s).\n",
898             usrblk.retncode, retncode_str (usrblk.retncode));
899         fflush (aa_stderr);
900     }
901     return;
902 }  /* Opera_Engine() */
903
904 /******************************* DTOE.C ********************************/