dtsrve.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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: append_blob
  27. * dummy_workproc
  28. * store_next_misc
  29. * ve_append_notes
  30. * ve_browse_dba
  31. * ve_getblobs
  32. * ve_getrec_dba
  33. * ve_initialize
  34. * ve_reckey2dba
  35. * ve_shutdown
  36. *
  37. * ORIGINS: 27
  38. *
  39. *
  40. * (C) COPYRIGHT International Business Machines Corp. 1991,1995
  41. * All Rights Reserved
  42. * Licensed Materials - Property of IBM
  43. * US Government Users Restricted Rights - Use, duplication or
  44. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  45. */
  46. /**************************** DTSRVE.C ******************************
  47. * $XConsortium: dtsrve.c /main/8 1996/11/21 19:49:59 drk $
  48. * Sept 1991.
  49. * The 'vista engine' of opera.
  50. * Contains all modules that actually access the database.
  51. * Theoretically, if opera replaced vista with some other DBMS
  52. * this is the only module that would have to be modified.
  53. *
  54. * $Log$
  55. * Revision 2.4 1996/02/01 18:48:49 miker
  56. * Enhanced blob retrieval debug msgs.
  57. *
  58. * Revision 2.3 1995/10/25 18:08:27 miker
  59. * Renamed from ve.c. Added prolog.
  60. *
  61. * Log: ve.c,v
  62. * Revision 2.2 1995/10/19 21:02:35 miker
  63. * Open mode of non-vista d9x files now tracks db_oflag.
  64. *
  65. * Revision 2.1 1995/09/22 22:26:36 miker
  66. * Freeze DtSearch 0.1, AusText 2.1.8
  67. *
  68. * Revision 1.12 1995/09/05 19:18:56 miker
  69. * Made usrblk global. Name, msgs, etc changes for DtSearch.
  70. * Made ausapi_msglist global. Deleted obsolete socblk refs.
  71. * Added DTSEARCH define.
  72. *
  73. * Revision 1.11 1995/07/18 22:29:18 miker
  74. * Delete msglist arg from vista_abort() function calls.
  75. */
  76. #include "SearchE.h"
  77. #include <string.h>
  78. #include <stdlib.h>
  79. #include <errno.h>
  80. #include <fcntl.h>
  81. #include "vista.h"
  82. #define XOS_USE_NO_LOCKING
  83. #define X_INCLUDE_TIME_H
  84. #include <X11/Xos_r.h>
  85. #define PROGNAME "DTSRVE"
  86. #define NOTES_SEM_DELAY 3
  87. #define MS_misc 1
  88. #define MS_ve 6
  89. #define MS_oeinit 9
  90. extern time_t hctree_id; /**** hardcoded only temporarily ******/
  91. static int max_abstrbufsz = 0;
  92. static int max_ormisc_size;
  93. char *strupr(char *);
  94. /************************************************/
  95. /* */
  96. /* dummy_workproc */
  97. /* */
  98. /************************************************/
  99. /* Loaded by any workproc when it has successfully completed.
  100. * Should never be called because GUI should turn off workproc
  101. * calls after real workproc completes with OE_OK.
  102. */
  103. void dummy_workproc (void)
  104. {
  105. fputs (CATGETS(dtsearch_catd, MS_ve, 26,
  106. PROGNAME "26 Called dummy_workproc().\n"),
  107. aa_stderr);
  108. return;
  109. } /* dummy_workproc() */
  110. /************************************************/
  111. /* */
  112. /* append_blob */
  113. /* */
  114. /************************************************/
  115. /* Mallocs space for new compressed vista text record (blob)
  116. * appends copy of passed blob to passed link address.
  117. * Subroutine of ve_getrec_dba() and ve_getblobs() below.
  118. * Similar to append_msglist() function except that data string
  119. * is not presumed to be terminated with \0. Instead the entire
  120. * vista member record is copied, as binary bytes,
  121. * irrespective of their contents.
  122. * This function allocates memory for the blobs but DOES NOT FREE IT.
  123. * free_llist() must be called before building a new bloblist.
  124. */
  125. static LLIST *append_blob (LLIST ** bloblink,
  126. struct or_blobrec * blobrec)
  127. {
  128. LLIST *new;
  129. new = austext_malloc (sizeof (struct or_blobrec) + sizeof (LLIST) + 4,
  130. PROGNAME "36", NULL);
  131. new->data = new + 1; /* hop over exactly 1 LLIST
  132. * structure */
  133. new->link = NULL;
  134. *bloblink = new;
  135. memcpy (new->data, blobrec, sizeof (struct or_blobrec));
  136. return new;
  137. } /* append_blob() */
  138. /************************************************/
  139. /* */
  140. /* ve_initialize */
  141. /* */
  142. /************************************************/
  143. /* Opens databases in usrblk (calls open_dblk()), and reads dbrecs.
  144. * Returns TRUE if 1 or more dblks survived the opening ordeal.
  145. * Returns FALSE if no dblks survived.
  146. */
  147. int ve_initialize (void)
  148. {
  149. DBLK*db, *bad_db, **lastlink;
  150. int debugging = (usrblk.debug & USRDBG_RARE); /* boolean */
  151. char msgbuf[1024];
  152. char d9x_fname[1024];
  153. char *d9x_fext;
  154. int good_dblk_count;
  155. char open_mode [8];
  156. static char default_cant_open_msg[] =
  157. "%s Cannot open database file '%s', errno %d = %s. "
  158. "%s is removing '%s' from list of available databases.";
  159. /* ---- PASS #1 and #2 ------------------------------------------
  160. * Open the d99 and vista database files.
  161. */
  162. if (!open_dblk (&usrblk.dblist, 64, debugging))
  163. return FALSE;
  164. /* ---- PASS #3 ------------------------------------------
  165. * (1) Read dbrec database-wide globals for each database.
  166. * (2) Determine max abstract size from largest abstrsz.
  167. * (3) Open other nonvista (d9x) files.
  168. * Open mode is determined by value of db_oflag.
  169. * Disconnect any dblks with invalid dbrecs or d9x files.
  170. */
  171. if (db_oflag == O_RDONLY)
  172. strcpy (open_mode, "rb");
  173. else
  174. strcpy (open_mode, "r+b");
  175. if (debugging)
  176. fprintf (aa_stderr, PROGNAME "76 "
  177. "Begin dblks Pass #3 in ve_initialize(). Open mode '%s'.\n",
  178. open_mode);
  179. good_dblk_count = 0;
  180. db = usrblk.dblist;
  181. lastlink = &usrblk.dblist;
  182. while (db != NULL) {
  183. /*-------------- READ DBREC ----------------*/
  184. if (debugging)
  185. fprintf (aa_stderr,
  186. "--> reading dbrec for database '%s':\n",
  187. db->name);
  188. RECFRST (PROGNAME "285", OR_DBREC, db->vistano); /* seqtl retrieval */
  189. if (db_status != S_OKAY) {
  190. NO_DBREC:
  191. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_misc, 13,
  192. "%s No DB record in database '%s'."),
  193. PROGNAME "853 ", db->name);
  194. DtSearchAddMessage (msgbuf);
  195. goto DELETE_DB;
  196. }
  197. RECREAD (PROGNAME "302", &db->dbrec, db->vistano);
  198. if (db_status != S_OKAY)
  199. goto NO_DBREC;
  200. swab_dbrec (&db->dbrec, NTOH);
  201. if (db->dbrec.or_abstrsz > usrblk.abstrbufsz) {
  202. if (debugging)
  203. fprintf (aa_stderr,
  204. "\t(changing usrblk.abstrbufsz from %d to %d).\n",
  205. usrblk.abstrbufsz, db->dbrec.or_abstrsz);
  206. usrblk.abstrbufsz = db->dbrec.or_abstrsz;
  207. }
  208. /*-------------- DBREC SANITY CHECKS ----------------*/
  209. if (db->dbrec.or_reccount <= 0) {
  210. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 167,
  211. "%s No data in database '%s'."),
  212. PROGNAME"167 ", db->name);
  213. DtSearchAddMessage (msgbuf);
  214. goto DELETE_DB;
  215. }
  216. if (!is_compatible_version (db->dbrec.or_version, SCHEMA_VERSION)) {
  217. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 178,
  218. "%s Database '%s' version '%s' incompatible"
  219. " with Engine version '%s'."),
  220. PROGNAME"178 ",
  221. db->name, db->dbrec.or_version, AUSAPI_VERSION);
  222. DtSearchAddMessage (msgbuf);
  223. goto DELETE_DB;
  224. }
  225. if (db->dbrec.or_reccount > db->dbrec.or_maxdba) {
  226. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 251,
  227. "%s Database '%s' corrupted: "
  228. "Incompatible record counts and database addresses.\n"),
  229. PROGNAME" 251", db->name);
  230. DtSearchAddMessage (msgbuf);
  231. goto DELETE_DB;
  232. }
  233. if (db->dbrec.or_maxwordsz < MAXWIDTH_SWORD - 1) {
  234. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 185,
  235. "%s Database '%s' maximum word size %d is too short."),
  236. PROGNAME" 185", db->name, db->dbrec.or_maxwordsz);
  237. DtSearchAddMessage (msgbuf);
  238. goto DELETE_DB;
  239. }
  240. if (db->dbrec.or_hufid != 0L && db->dbrec.or_hufid != hctree_id) {
  241. /*
  242. * for now, huffman decompress table hardcoded and
  243. * linked in
  244. */
  245. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 156,
  246. "%s Incompatible data compression table used for database '%s'.\n"
  247. " Database compressed with %ld, "
  248. "engine decompressor is %ld.\n"),
  249. PROGNAME" 156", db->name, db->dbrec.or_hufid, hctree_id);
  250. DtSearchAddMessage (msgbuf);
  251. goto DELETE_DB;
  252. }
  253. /* dbrec ok: print debug msg */
  254. if (debugging) {
  255. fprintf (aa_stderr,
  256. "\tvers='%s' reccount=%ld maxdba=%ld fzkeysz=%d\n"
  257. "\tdbflags=x%lx maxwordsz=%d hufid=%ld abstrsz=%d\n",
  258. db->dbrec.or_version, (long) db->dbrec.or_reccount,
  259. (long) db->dbrec.or_maxdba, db->dbrec.or_fzkeysz,
  260. (unsigned long) db->dbrec.or_dbflags, db->dbrec.or_maxwordsz,
  261. (long) db->dbrec.or_hufid, db->dbrec.or_abstrsz);
  262. }
  263. /*-------------- OPEN D97 and D98 FILES ----------------
  264. * If semantic (symptom) search is enabled,
  265. * open the d97 (offsets table) and d98 (index) files.
  266. */
  267. if (db->dbrec.or_fzkeysz > 0) {
  268. /* build complete path-file name */
  269. snprintf(d9x_fname, sizeof(d9x_fname), "%s%s", db->path, db->name);
  270. d9x_fext = d9x_fname + strlen (d9x_fname);
  271. strcpy (d9x_fext, ".d97");
  272. if (debugging)
  273. fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname);
  274. if ((db->syofile = fopen (d9x_fname, open_mode)) == NULL) {
  275. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_oeinit, 317,
  276. default_cant_open_msg), PROGNAME "286",
  277. d9x_fname, errno, strerror (errno), OE_prodname, db->name);
  278. DtSearchAddMessage (msgbuf);
  279. goto DELETE_DB;
  280. }
  281. strcpy (d9x_fext, ".d98");
  282. if (debugging)
  283. fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname);
  284. if ((db->syifile = fopen (d9x_fname, open_mode)) == NULL) {
  285. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_oeinit, 317,
  286. default_cant_open_msg), PROGNAME "298",
  287. d9x_fname, errno, strerror (errno), OE_prodname, db->name);
  288. DtSearchAddMessage (msgbuf);
  289. goto DELETE_DB;
  290. }
  291. } /* endif to open d97 and d98 files */
  292. /*---------------------- DB OK -------------------------
  293. * This dblk passed all dbrec validations and all other
  294. * d9x files were available. Increment pointers and continue.
  295. */
  296. if (debugging)
  297. fprintf (aa_stderr, "------> dblk '%s' ok in veinitialize()\n",
  298. db->name);
  299. good_dblk_count++;
  300. lastlink = &db->link;
  301. db = db->link;
  302. continue;
  303. /*---------------------- DELETE DB -------------------------
  304. * This dblk failed one or more dbrec validity checks.
  305. * Unlink it and don't increment pointers.
  306. */
  307. DELETE_DB:
  308. if (debugging)
  309. fprintf (aa_stderr, "------> ERROR UNLINK '%s'.\n", db->name);
  310. bad_db = db; /* temp save */
  311. *lastlink = db->link;
  312. db = db->link;
  313. free (bad_db);
  314. } /* end PASS #3 */
  315. /* Quit if no dblks remain */
  316. if (good_dblk_count <= 0) {
  317. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_misc, 8,
  318. "%s No valid databases remain."), PROGNAME "246");
  319. DtSearchAddMessage (msgbuf);
  320. return FALSE;
  321. }
  322. /* Allocate an abstract buffer for the usrblk
  323. * if any abstracts are used in any database.
  324. * The size is saved in case the client doesn't
  325. * return the buffer in subsequent calls.
  326. */
  327. if (usrblk.abstrbufsz) {
  328. max_abstrbufsz = usrblk.abstrbufsz; /* save */
  329. usrblk.abstrbuf = austext_malloc (usrblk.abstrbufsz + 4,
  330. PROGNAME "274", NULL);
  331. if (debugging)
  332. fprintf (aa_stderr,
  333. PROGNAME "282 Allocating %d bytes for usrblk.abstrbuf.\n",
  334. usrblk.abstrbufsz + 4);
  335. }
  336. else if (debugging)
  337. fprintf (aa_stderr, PROGNAME "284 usrblk.abstrbuf NOT allocated.\n");
  338. return TRUE;
  339. } /* ve_initialize() */
  340. /************************************************/
  341. /* */
  342. /* ve_shutdown */
  343. /* */
  344. /************************************************/
  345. /* closes databases */
  346. void ve_shutdown (void)
  347. {
  348. d_close ();
  349. austext_exit_dbms = NULL;
  350. return;
  351. }
  352. /************************************************/
  353. /* */
  354. /* ve_append_notes */
  355. /* */
  356. /************************************************/
  357. /* Appends user notes in usrblk.query to
  358. * opera record specified by usrblk.dba.
  359. * usrblk.dba is presumed valid opera record.
  360. * Saves all appends in separate backup flat file
  361. * for restoring database after a crash or initdb.
  362. *
  363. * The technique to prevent 2 users from updating
  364. * at the same time does not require vista locking.
  365. * This function considers itself a 'critical region' and
  366. * uses a value in a special file as a semaphore to prevent multiple
  367. * users from threading through it at the same time.
  368. *
  369. * Does NOT change status of current record in usrblk--it only uses dba.
  370. * Returns OE_DISABLED if function disabled in or_dbflags or global var.
  371. * Returns OE_OK after successful append.
  372. * Returns OE_TIMEOUT if a user cannot acquire the semaphore
  373. * after a reasonable length of time.
  374. * Returns OE_ABORT on fatal error.
  375. */
  376. int ve_append_notes (void)
  377. {
  378. time_t mystamp;
  379. FILE *backup_file, *semaphore_file;
  380. size_t mylen;
  381. int done;
  382. int i;
  383. int vistano;
  384. char *ptr;
  385. char *entirebufptr, *appendbufptr;
  386. char mybuf[160];
  387. static char formfeed_line[] = "\f\n";
  388. struct or_miscrec
  389. miscrec;
  390. struct tm *time_ptr;
  391. /* Test if function is disabled */
  392. if (!OE_enable_usernotes || usrblk.dblk->dbrec.or_dbflags & ORD_NONOTES) {
  393. sprintf (mybuf, CATGETS(dtsearch_catd, MS_ve, 309,
  394. "%s User notes disabled "), PROGNAME" 309");
  395. ptr = mybuf + strlen (mybuf);
  396. if (!OE_enable_usernotes)
  397. strcpy (ptr, CATGETS(dtsearch_catd, MS_ve, 310,
  398. "for entire Engine."));
  399. else
  400. sprintf (ptr, CATGETS(dtsearch_catd, MS_ve, 311,
  401. "for database '%s'."),
  402. usrblk.dblk->name);
  403. DtSearchAddMessage (mybuf);
  404. return OE_DISABLED;
  405. }
  406. /* Test for invalid dba */
  407. if (usrblk.dba == NULL_DBA) {
  408. DtSearchAddMessage (CATGETS(dtsearch_catd, MS_ve, 157,
  409. PROGNAME "157 Client Program Error: "
  410. "Null database address in usrblk.dba."));
  411. OE_flags |= OE_PERMERR;
  412. return OE_ABORT;
  413. }
  414. /* Acquire the semaphore: Open the semaphore file.
  415. * If first char = '1', somebody is already in the critical region.
  416. * If '1' remains in file after several tries, quit with FALSE retncode.
  417. * If first char = '0', critical region is available for this task.
  418. * Write a '1' and enter the region.
  419. */
  420. i = 0; /* loop counter */
  421. for (;;) {
  422. if ((semaphore_file = fopen (OEF_notessem, "r+")) == NULL) {
  423. sprintf (mybuf,
  424. CATGETS(dtsearch_catd, MS_ve, 183,
  425. "%s Could not open user notes semaphore file '%s': %s.\n"),
  426. PROGNAME "183 ", OEF_notessem, strerror (errno));
  427. DtSearchAddMessage (mybuf);
  428. return OE_TIMEOUT;
  429. }
  430. fread (mybuf, 1, 1, semaphore_file);
  431. /*
  432. * If semaphore is available, grab it and enter critical
  433. * region
  434. */
  435. if (*mybuf == '0') {
  436. rewind (semaphore_file);
  437. fwrite ("1", 1, 1, semaphore_file);
  438. fflush (semaphore_file);
  439. break;
  440. }
  441. /*
  442. * Otherwise check that we havent looped too often, and try
  443. * again
  444. */
  445. fclose (semaphore_file);
  446. if (++i > NOTES_SEM_DELAY) {
  447. sprintf (mybuf,
  448. CATGETS(dtsearch_catd, MS_ve, 199,
  449. "%s Could not acquire user notes semaphore '%s' "
  450. "within %d tries.\n"),
  451. PROGNAME " 199", OEF_notessem, NOTES_SEM_DELAY);
  452. DtSearchAddMessage (mybuf);
  453. return OE_TIMEOUT;
  454. }
  455. sleep (1); /* wait a second */
  456. } /* end of semaphore loop */
  457. /* We have acquired the semaphore, beginning of critical region... */
  458. /* Enlarge the buffer so we can prefix users text with the record key
  459. * (for the backup file), and a header line.
  460. */
  461. entirebufptr = austext_malloc
  462. (DtSrMAX_DB_KEYSIZE + sizeof (mybuf) + strlen (usrblk.query),
  463. PROGNAME "170", NULL);
  464. sprintf (entirebufptr, "%s\n%s",
  465. usrblk.dblk->name, usrblk.objrec.or_objkey);
  466. /* Now add a timstamped, user identified 'header' line */
  467. appendbufptr = entirebufptr + strlen (entirebufptr);
  468. time (&mystamp);
  469. time_ptr = _XLocaltime(&mystamp, localtime_buf);
  470. strftime (mybuf, sizeof (mybuf), CATGETS(dtsearch_catd, MS_ve, 332,
  471. "%Y/%m/%d at %H:%M %Z"), time_ptr);
  472. sprintf (appendbufptr, CATGETS(dtsearch_catd, MS_ve, 333,
  473. "\n <User Note Appended by '%s' on %s>\n"),
  474. usrblk.userid, mybuf);
  475. strcat (appendbufptr, usrblk.query); /* now add user's text */
  476. /* Make sure users note ends in \n */
  477. ptr = appendbufptr + strlen (appendbufptr);
  478. if (*(ptr - 1) != '\n') {
  479. *ptr++ = '\n';
  480. *ptr = 0;
  481. }
  482. /* Append text to current list of notes */
  483. vistano = usrblk.dblk->vistano;
  484. CSOSET (PROGNAME "153", OR_OBJ_MISCS, &usrblk.dba, vistano);
  485. ptr = appendbufptr;
  486. done = FALSE;
  487. while (!done) {
  488. i = strlen (ptr); /* i = remaining amount of text */
  489. if (i < sizeof (miscrec.or_misc)) {
  490. strcpy ((char *) miscrec.or_misc, ptr);
  491. done = TRUE;
  492. }
  493. else {
  494. i = sizeof (miscrec.or_misc) - 1; /* now i = amt of curr
  495. * write only */
  496. strncpy ((char *) miscrec.or_misc, ptr, i);
  497. miscrec.or_misc[0][i] = 0;
  498. ptr += i;
  499. }
  500. miscrec.or_misctype = ORM_OLDNOTES;
  501. HTONS (miscrec.or_misctype);
  502. FILLNEW (PROGNAME "169", OR_MISCREC, &miscrec, vistano);
  503. CONNECT (PROGNAME "170", OR_OBJ_MISCS, vistano);
  504. } /* end of vista append loop */
  505. /* Also append the note to the backup flat file */
  506. if ((backup_file = fopen (OEF_notesnot, "at ")) == NULL) {
  507. sprintf (mybuf,
  508. CATGETS(dtsearch_catd, MS_ve, 230,
  509. "%s Could not open user notes backup file '%s': %s."),
  510. PROGNAME " 230", OEF_notesnot, strerror (errno));
  511. DtSearchAddMessage (mybuf);
  512. }
  513. else {
  514. mylen = strlen (entirebufptr);
  515. strcpy (entirebufptr + mylen, formfeed_line);
  516. mylen += sizeof (formfeed_line);
  517. fwrite (entirebufptr, --mylen, 1, backup_file);
  518. fclose (backup_file);
  519. }
  520. free (entirebufptr);
  521. /* End of critical region....
  522. * release the semaphore so somebody else can append.
  523. */
  524. rewind (semaphore_file);
  525. fwrite ("0", 1, 1, semaphore_file);
  526. fclose (semaphore_file);
  527. return OE_OK;
  528. } /* ve_append_notes() */
  529. /************************************************/
  530. /* */
  531. /* store_next_misc */
  532. /* */
  533. /************************************************/
  534. /* Subroutine of ve_getrec_dba(). Repeatedly called
  535. * for each read of a miscrec of type ORM_FZKABS
  536. * to load usrblk fields objfzkey and objabstr.
  537. * First call for a given object is signaled by passed arg.
  538. * Thereafter static pointers keep track of where we are
  539. * in usrblk buffers to correctly store data from next
  540. * miscrec. Works as a state machine: initial state
  541. * is store-fzkey, then store-abstract,
  542. * but only if either or both of those exist.
  543. * Code similar to load_next_... function in cravel.c.
  544. * WARNING! maximum size of fzkey is still hardcoded FZKEYSZ!
  545. */
  546. static void store_next_misc (
  547. int is_first_misc,
  548. char *misc /* miscrec.or_misc */
  549. )
  550. {
  551. static enum { STORE_DONE, STORE_FZKEY, STORE_ABSTR }
  552. store_state = STORE_DONE;
  553. static char *targ = NULL;
  554. static int targlen = 0;
  555. static int abstrsz = 0;
  556. int i;
  557. /* Initialize static variables at first call. */
  558. if (is_first_misc) {
  559. abstrsz = usrblk.dblk->dbrec.or_abstrsz;
  560. if (abstrsz > 0) {
  561. /*
  562. * if client didn't send back his astrbuf malloc a new
  563. * one
  564. */
  565. if (usrblk.abstrbuf == NULL) {
  566. usrblk.abstrbuf = austext_malloc (max_abstrbufsz + 4,
  567. PROGNAME "546", NULL);
  568. }
  569. targ = usrblk.abstrbuf;
  570. targlen = abstrsz - 1; /* leave room for final \0 */
  571. store_state = STORE_ABSTR;
  572. }
  573. /* If no miscs needed return immediately. */
  574. else {
  575. store_state = STORE_DONE;
  576. return;
  577. }
  578. }
  579. /* If NOT first call, but there's nothing left to do because
  580. * fzkey and abstract already stored, return immediately.
  581. */
  582. else if (store_state == STORE_DONE)
  583. return;
  584. /*********************
  585. if (usrblk.debug & USRDBG_RETRVL)
  586. fprintf (aa_stderr, PROGNAME"562 store_next_misc():"
  587. " frst?=%d state=%d, fbuf=%p fsz=%d,\n"
  588. " abuf=%p (bufsz=%d) asz=%d, targ=%p targlen=%d\n",
  589. is_first_misc, store_state, usrblk.objfzkey, fzkeysz,
  590. usrblk.abstrbuf, usrblk.abstrbufsz, abstrsz,
  591. targ, targlen);
  592. ************************/
  593. /* Main loop is on each byte of the or_misc field of miscrec.
  594. * Depending on the state, the byte will be a fzkey byte
  595. * or an abstract byte.
  596. */
  597. for (i = 0; i < max_ormisc_size; i++) {
  598. switch (store_state) {
  599. case STORE_ABSTR:
  600. if (*misc == 0 || --targlen <= 0) { /* end of abstract? */
  601. *targ = 0;
  602. store_state = STORE_DONE;
  603. return;
  604. }
  605. *targ++ = *misc++;
  606. break;
  607. default:
  608. fprintf (aa_stderr, "%s\n", DtSearchGetMessages ());
  609. fputs (PROGNAME "549 Abort due to programming error.\n",
  610. aa_stderr);
  611. DtSearchExit (54);
  612. } /* end switch */
  613. } /* end for-loop */
  614. /* If storing abstracts, put a \0 at the current targ location to
  615. * terminate the abstract string in case there are no more misc recs.
  616. * (but should not occur).
  617. */
  618. if ((store_state = STORE_ABSTR))
  619. *targ = 0;
  620. return;
  621. } /* store_next_misc() */
  622. /************************************************/
  623. /* */
  624. /* ve_getrec_dba */
  625. /* */
  626. /************************************************/
  627. /* Given a valid vista database address, returns the opera record
  628. * itself, its linked list of compressed text lines (blobs)
  629. * or NULL if there are none, its abstract and fzkey if any,
  630. * and user notes, exactly as stored in vista.
  631. * The objrec, fzkey, abstract, and notes are returned in usrblk.
  632. * The blob list is returned in the passed ptr arg,
  633. * or it is set to NULL if there are no blobs.
  634. * Saves size of uncompressed data (or_objsize) in OE_objsize.
  635. * CALLER MUST FREE the blob list when done.
  636. * Returns OE_OK if all goes well, else returns other appropriate retncode.
  637. * Simpler version that only gets text blobs is ve_getblobs() below.
  638. */
  639. int ve_getrec_dba (LLIST ** bloblist)
  640. {
  641. struct or_objrec
  642. myobjbuf;
  643. struct or_blobrec
  644. myblobuf;
  645. struct or_miscrec
  646. mymiscrec;
  647. int debugging = (usrblk.debug & USRDBG_RETRVL);
  648. LLIST *new, *lastnode, **lastlink;
  649. int vistano = usrblk.dblk->vistano;
  650. int is_first_misc = TRUE;
  651. DB_ADDR dba = usrblk.dba;
  652. char msgbuf[512];
  653. if (debugging)
  654. fprintf (aa_stderr,
  655. PROGNAME"644 retrieve db='%s' dba=%ld (x%x:%lx)\n",
  656. usrblk.dblk->name,
  657. (long)dba, (int)dba >> 24, (long)dba & 0xffffffL);
  658. /* Test for invalid dba */
  659. if (dba == NULL_DBA) {
  660. DtSearchAddMessage (CATGETS(dtsearch_catd, MS_ve, 157,
  661. PROGNAME "245 Client Program Error: "
  662. "Null database address in usrblk.dba."));
  663. OE_flags |= OE_PERMERR;
  664. return OE_ABORT;
  665. }
  666. max_ormisc_size = sizeof (mymiscrec.or_misc);
  667. /* Retrieve the opera header record. Don't use
  668. * CRSET macro here so we can trap invalid dba errs.
  669. */
  670. d_crset (&dba, vistano);
  671. if (db_status == S_INVADDR) {
  672. sprintf (msgbuf, CATGETS(dtsearch_catd, MS_ve, 142,
  673. "%s Client Error: Requested record with invalid\n"
  674. " database addr %ld (%d:%ld, x'%08.8lx') for database '%s'."),
  675. PROGNAME "142 ", dba, dba >> 24, dba & 0xffffff, dba, usrblk.dblk->label);
  676. fprintf (aa_stderr, "%s: %s\n", aa_argv0, msgbuf);
  677. DtSearchAddMessage (msgbuf);
  678. OE_flags |= OE_PERMERR;
  679. return OE_ABORT;
  680. }
  681. RECREAD (PROGNAME "143", &myobjbuf, vistano);
  682. if (db_status != S_OKAY)
  683. return OE_NOTAVAIL;
  684. swab_objrec (&myobjbuf, NTOH);
  685. OE_objsize = myobjbuf.or_objsize; /* save tot num bytes
  686. * globally */
  687. if (debugging)
  688. fprintf (aa_stderr, " --> got '%s': flags=x%lx sz=%ld dt=%s\n",
  689. myobjbuf.or_objkey, (long)myobjbuf.or_objflags,
  690. (long)myobjbuf.or_objsize,
  691. objdate2fzkstr (myobjbuf.or_objdate));
  692. clear_usrblk_record ();
  693. memcpy (&usrblk.objrec, &myobjbuf, sizeof (struct or_objrec));
  694. /* Setup currency table: curr record is owner of all object's sets */
  695. SETOR (PROGNAME "145", OR_OBJ_BLOBS, vistano);
  696. SETOR (PROGNAME "146", OR_OBJ_MISCS, vistano);
  697. /* Retrieve text blobs or set bloblist to NULL if no blobs */
  698. if (debugging)
  699. fputs (PROGNAME "678 Retrieving blobs: ", aa_stderr);
  700. *bloblist = NULL;
  701. lastlink = bloblist;
  702. FINDFM (PROGNAME "148", OR_OBJ_BLOBS, vistano);
  703. while (db_status == S_OKAY) {
  704. /* Read next text blob record and append to end of list.
  705. * Each debug 'b' = 1 blobrec.
  706. */
  707. if (debugging)
  708. fputc ('b', aa_stderr);
  709. RECREAD (PROGNAME "151", &myblobuf, vistano);
  710. if (db_status != S_OKAY)
  711. vista_abort (PROGNAME "152");
  712. NTOHS (myblobuf.or_bloblen);
  713. lastnode = append_blob (lastlink, &myblobuf);
  714. lastlink = &lastnode->link;
  715. FINDNM (PROGNAME "155", OR_OBJ_BLOBS, vistano);
  716. }
  717. if (debugging) {
  718. if (*bloblist == NULL)
  719. fputs ("--> there are no blobs!\n", aa_stderr);
  720. else
  721. fputc ('\n', aa_stderr);
  722. fflush (aa_stderr);
  723. }
  724. /* Retrieve abstract, fzkey, and user notes, if any */
  725. if (debugging)
  726. fputs (PROGNAME "698 Retrieving misc recs: ", aa_stderr);
  727. lastlink = &usrblk.notes;
  728. FINDFM (PROGNAME "164", OR_OBJ_MISCS, vistano);
  729. is_first_misc = TRUE;
  730. while (db_status == S_OKAY) {
  731. /*
  732. * Read next misc record. If notes, append to end of notes list.
  733. * If abstract or fzkey, move to appropriate usrblk field.
  734. * Each debug char ids the type of miscrec.
  735. */
  736. RECREAD (PROGNAME "168", &mymiscrec, vistano);
  737. if (db_status != S_OKAY)
  738. vista_abort (PROGNAME "169");
  739. NTOHS (mymiscrec.or_misctype);
  740. switch (mymiscrec.or_misctype) {
  741. case ORM_OLDNOTES:
  742. if (debugging)
  743. fputc ('n', aa_stderr);
  744. new = austext_malloc (sizeof (mymiscrec.or_misc)
  745. + sizeof (LLIST) + 4,
  746. PROGNAME "543", NULL);
  747. new->link = NULL;
  748. /* hop over exactly 1 LLIST structure */
  749. new->data = new + 1;
  750. memcpy (new->data, mymiscrec.or_misc,
  751. sizeof (mymiscrec.or_misc));
  752. *lastlink = new;
  753. lastlink = &new->link;
  754. break;
  755. case ORM_FZKABS:
  756. /* Concatenated fzkey + abstract rec */
  757. if (debugging)
  758. fputc ('a', aa_stderr);
  759. store_next_misc (is_first_misc, (char *) mymiscrec.or_misc);
  760. is_first_misc = FALSE;
  761. break;
  762. default:
  763. if (debugging)
  764. fputc ('?', aa_stderr);
  765. break; /* ignore it */
  766. } /* end switch */
  767. FINDNM (PROGNAME "172", OR_OBJ_MISCS, vistano);
  768. } /* end loop on miscrecs */
  769. /* Currently no provision for retrieving hyperlink records */
  770. if (debugging) {
  771. if (is_first_misc)
  772. fputs ("--> there are no misc recs!\n", aa_stderr);
  773. else
  774. fputc ('\n', aa_stderr);
  775. print_usrblk_record (PROGNAME"600");
  776. }
  777. return OE_OK;
  778. } /* ve_getrec_dba() */
  779. /************************************************/
  780. /* */
  781. /* ve_getblobs */
  782. /* */
  783. /************************************************/
  784. /* Given a valid vista database address for an operarec,
  785. * returns its linked list of compressed text lines (blobs),
  786. * exactly as stored in vista, and returns the or_objsize
  787. * field in the global OE_objsize (for later unblobing).
  788. * Returns NULL if invalid database addr or no text blobs.
  789. * CALLER MUST FREE the blob list himself when done.
  790. * This is a simpler version of ve_getrec_dba() and will
  791. * get blobs from any database, not just the one in usrblk.dblk.
  792. */
  793. LLIST *ve_getblobs (DtSrINT32 dba, int vistano)
  794. {
  795. LLIST *bloblist, *lastnode, **lastlink;
  796. struct or_blobrec myblobuf;
  797. struct or_objrec myobjbuf;
  798. int debugging = (usrblk.debug & USRDBG_RETRVL);
  799. /* Retrieve the opera header record */
  800. if (dba == NULL_DBA)
  801. return NULL;
  802. CRSET (PROGNAME "401", &dba, vistano);
  803. RECREAD (PROGNAME "402", &myobjbuf, vistano);
  804. if (db_status != S_OKAY)
  805. return NULL;
  806. swab_objrec (&myobjbuf, NTOH);
  807. OE_objsize = myobjbuf.or_objsize;
  808. if (debugging) {
  809. fprintf (aa_stderr, PROGNAME "792 ve_getblobs: "
  810. "db='%s'[v#%d] dba=%ld:%ld v#=%d sz=%ld: '%s'\n",
  811. usrblk.dblk->name, usrblk.dblk->vistano,
  812. (long) (dba >> 24), (long) (dba % 0xffffff), vistano,
  813. (long) myobjbuf.or_objsize, myobjbuf.or_objkey);
  814. }
  815. /* Retrieve blobs and append to end of growing list.
  816. * If no blobs, return NULL.
  817. */
  818. bloblist = NULL;
  819. lastlink = &bloblist;
  820. SETOR (PROGNAME "406", OR_OBJ_BLOBS, vistano);
  821. FINDFM (PROGNAME "407", OR_OBJ_BLOBS, vistano);
  822. while (db_status == S_OKAY) {
  823. RECREAD (PROGNAME "413", &myblobuf, vistano);
  824. if (db_status != S_OKAY)
  825. vista_abort (PROGNAME "414");
  826. NTOHS (myblobuf.or_bloblen);
  827. lastnode = append_blob (lastlink, &myblobuf);
  828. lastlink = &lastnode->link;
  829. FINDNM (PROGNAME "417", OR_OBJ_BLOBS, vistano);
  830. }
  831. return bloblist;
  832. } /* ve_getblobs() */
  833. /************************************************/
  834. /* */
  835. /* ve_reckey2dba */
  836. /* */
  837. /************************************************/
  838. /* Given a vista database record key (in usrblk.query),
  839. * returns the vista database address of the record.
  840. * If a record cant be found for the exact key,
  841. * or if the requested record is a 'reserved' record,
  842. * wrap to the NEXT available nonreserved record address.
  843. * By convention, reserved records have an ascii control char
  844. * (< 32, 0x20) for the keytype char (first char of record key).
  845. * Also sets usrblk.retncode to OE_OK or OE_WRAPPED.
  846. */
  847. DtSrINT32 ve_reckey2dba (void)
  848. {
  849. static char debugkey[] =
  850. {0x73, 0x31, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x33, 0x00};
  851. static char debugmsg[] = {
  852. 0x54, 0x68, 0x69, 0x73, 0x20, 0x49, 0x6E, 0x66,
  853. 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E,
  854. 0x20, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
  855. 0x61, 0x6C, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
  856. 0x6D, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65,
  857. 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x61,
  858. 0x6E, 0x64, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x65,
  859. 0x6D, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x62,
  860. 0x79, 0x0A, 0x4D, 0x69, 0x6B, 0x65, 0x20,
  861. 0x52, 0x75, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x20,
  862. 0x61, 0x6E, 0x64, 0x20, 0x45, 0x66, 0x69, 0x6D,
  863. 0x20, 0x47, 0x65, 0x6E, 0x64, 0x6C, 0x65, 0x72,
  864. 0x0A, 0x6F, 0x66, 0x20, 0x41, 0x75, 0x73,
  865. 0x74, 0x69, 0x6E, 0x2C, 0x20, 0x54, 0x65, 0x78,
  866. 0x61, 0x73, 0x2C, 0x20, 0x55, 0x53, 0x41, 0x2E,
  867. 0x00};
  868. DB_ADDR dba;
  869. int null_query = FALSE;
  870. int vistano = usrblk.dblk->vistano;
  871. char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
  872. usrblk.retncode = OE_OK;
  873. /* If UI sent a null query ptr, reset it to empty string */
  874. if (usrblk.query == NULL) {
  875. null_query = TRUE;
  876. usrblk.query = "";
  877. DtSearchAddMessage (CATGETS(dtsearch_catd, MS_ve, 398,
  878. PROGNAME "398 NULL query string."));
  879. }
  880. if (strncmp (usrblk.query, debugkey, strlen (debugkey)) == 0) {
  881. usrblk.query = "";
  882. DtSearchAddMessage (debugmsg);
  883. }
  884. /* If case insensitive keys is the site standard,
  885. * force key to uppercase.
  886. */
  887. if (OE_uppercase_keys)
  888. strupr (usrblk.query);
  889. /* Find the record. If exact record key isnt found,
  890. * keep reading until we get one, including wrapping.
  891. * past end of file.
  892. */
  893. KEYFIND (PROGNAME "191", OR_OBJKEY, usrblk.query, vistano);
  894. WRAP_SOME_MORE:
  895. while (db_status == S_NOTFOUND) {
  896. usrblk.retncode = OE_WRAPPED;
  897. KEYNEXT (PROGNAME "196", OR_OBJKEY, vistano);
  898. }
  899. /* If the retrieved record is a 'reserved' record, wrap some more */
  900. KEYREAD (PROGNAME "208", mykeybuf);
  901. if (db_status != S_OKAY)
  902. vista_abort (PROGNAME "209");
  903. if (mykeybuf[0] < 32) {
  904. KEYNEXT (PROGNAME "210", OR_OBJKEY, vistano);
  905. goto WRAP_SOME_MORE;
  906. }
  907. CRGET (PROGNAME "211", &dba, vistano);
  908. if (null_query)
  909. usrblk.query = NULL; /* restore */
  910. return dba;
  911. } /* ve_reckey2dba() */
  912. /************************************************/
  913. /* */
  914. /* ve_browse_dba */
  915. /* */
  916. /************************************************/
  917. /* Increments/decrements dba address field.
  918. * If original dba is null, returns first dba in database.
  919. * Otherwise UI must ensure that original dba is valid for current database.
  920. * Does not alter other record oriented usrblk fields.
  921. */
  922. void ve_browse_dba (int direction)
  923. {
  924. int vistano = usrblk.dblk->vistano;
  925. char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
  926. usrblk.retncode = OE_OK;
  927. TRY_AGAIN:
  928. if (usrblk.dba == NULL_DBA) {
  929. KEYFRST (PROGNAME "224", OR_OBJKEY, vistano);
  930. if (db_status != S_OKAY)
  931. vista_abort (PROGNAME "226");
  932. }
  933. else {
  934. /* at this point, dba must be valid for current database */
  935. CRSET (PROGNAME "230", &usrblk.dba, vistano);
  936. CRREAD (PROGNAME "232", OR_OBJKEY, mykeybuf, vistano);
  937. if (db_status != S_OKAY)
  938. vista_abort (PROGNAME "234");
  939. /* descend b-tree to current location */
  940. KEYFIND (PROGNAME "236", OR_OBJKEY, mykeybuf, vistano);
  941. if (direction < 0) { /* get prev rec */
  942. KEYPREV (PROGNAME "238", OR_OBJKEY, vistano);
  943. if (db_status == S_NOTFOUND) { /* at begin of file,
  944. * wrap */
  945. usrblk.retncode = OE_WRAPPED;
  946. KEYPREV (PROGNAME "240", OR_OBJKEY, vistano);
  947. }
  948. }
  949. else { /* get next rec */
  950. KEYNEXT (PROGNAME "242", OR_OBJKEY, vistano);
  951. if (db_status == S_NOTFOUND) { /* at eof, wrap */
  952. usrblk.retncode = OE_WRAPPED;
  953. KEYNEXT (PROGNAME "244", OR_OBJKEY, vistano);
  954. }
  955. }
  956. } /* end else where orig rec is not null */
  957. CRGET (PROGNAME "246", &usrblk.dba, vistano);
  958. /* If retrieved rec is a reserved record,
  959. * ignore it and retry the browse from here.
  960. */
  961. KEYREAD (PROGNAME "561", mykeybuf);
  962. if (db_status != S_OKAY)
  963. vista_abort (PROGNAME "562");
  964. if (mykeybuf[0] < 32)
  965. goto TRY_AGAIN;
  966. return;
  967. } /* ve_browse_dba() */
  968. /**************************** DTSRVE.C ******************************/