Fixes for OpenBSD
[oweals/cde.git] / cde / programs / dtinfo / dtinfogen / infolib / etc / BookTasks.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 /* $XConsortium: BookTasks.cc /main/5 1996/05/29 12:36:58 rcs $ 
24  *
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33
34
35 #include <sstream>
36 using namespace std;
37
38 /* import... */
39 #include <assert.h>
40 #include <string.h>
41 #include "Dispatch.h"
42 #include "Token.h"
43 #include "OLAF.h"
44 #include "NodeTask.h"
45 #include "TOCTask.h"
46 #include "BookCaseDB.h"
47 #include "OL-Data.h"
48 #include "StringList.h"
49 #include "StyleTask.h"
50 #include "api/utility.h"
51
52 /* export... */
53 #include "BookTasks.h"
54
55 #ifdef LICENSE_MANAGEMENT
56 #include "cryptlib/lterms.h"
57 #endif
58
59 #ifdef FISH_DEBUG
60 #include "dbug.h"  /* ala Fred Fish's dbug package from uunet */
61 #endif
62
63 const int A_FEATURE = OLAF::Feature;
64 const int A_VEN_CODE = OLAF::VenCode;
65 const int A_VERSION  = OLAF::Version;
66 const int A_GROUPING = OLAF::Grouping;
67 const int A_DEMO_TERMS = OLAF::DemoTerms;
68 const int A_DEFAULT_SECTION = OLAF::DefaultSection;
69
70 /***********************************
71  *
72  * BookCaseTask
73  *
74  ***********************************/
75   
76 BookCaseTask::BookCaseTask(const char *infolib)
77 {
78   int len = strlen(infolib);
79   library = new char[len + 1];
80   *((char *) memcpy(library, infolib, len) + len) = '\0';
81
82   f_base = -1;
83
84   bookCaseName = NULL;
85   bookCaseDesc = NULL;
86   
87   f_db = NULL;
88   
89   if ( !Dispatch::RunTocGenOnly() ) {
90     style = new StyleTaskDB(this);
91     addSubTask(style);
92   } else {
93     style = NULL;
94   }
95
96   book = new BookTask(this);
97   addSubTask(book);
98
99   f_style = NULL;
100   f_search_storage = NULL;
101 }
102
103
104 //--------------------------------------------------------------------
105 BookCaseDB*
106 BookCaseTask::database()
107 {
108   if(!f_db){
109     f_db = new BookCaseDB(library);
110   }
111
112   return f_db;
113 }
114
115
116 //--------------------------------------------------------------------
117 DBTable *
118 BookCaseTask::table(int tid)
119 {
120   return database()->table(tid);
121 }
122
123 //--------------------------------------------------------------------
124 const char *
125 BookCaseTask::bookcasename()
126 {
127   if ( !bookCaseName ) {
128     throw(Unexpected("BookCase name not available yet."));
129   }
130
131   return ( bookCaseName->content() );
132 }
133
134 /*
135 //--------------------------------------------------------------------
136 void
137 BookCaseTask::write_full_text_record( const char *str,
138                                       int sz,
139                                       const char *nodelocator,
140                                       const char *node_title
141  )
142 {
143   const char *BookCaseName = bookcasename();
144   
145   if ( !f_search_storage ) {
146     const char *pathname = database()->path();
147
148     f_search_storage = new FulcrumStore( pathname , BookCaseName);
149     assert ( f_search_storage );
150   }
151
152   const int   BookNum      = book->sequencenum();
153   const char  *BookShortTitle = book->book_short_title();
154
155   f_search_storage->insert( BookCaseName,
156                             BookNum,
157                             BookShortTitle,
158                             nodelocator,
159                             node_title,
160                             str,
161                             sz );
162 }
163 */
164 /*
165 //--------------------------------------------------------------------
166 void
167 BookCaseTask::write_full_text_record(DataRepository *store,
168                                      const char *nodelocator,
169                                      const char *node_title
170 )
171 {
172
173   const char *BookCaseName = bookcasename();
174
175   if ( !f_search_storage ) {
176     const char *pathname = database()->path();
177     f_search_storage = new AusTextStore( pathname, BookCaseName );
178     assert( f_search_storage );
179   }
180
181   const char  *BookShortTitle = book->book_short_title();
182   f_search_storage->insert( BookShortTitle,
183                             nodelocator,
184                             node_title,
185                             store
186                           );
187 }
188   
189 */  
190   
191 //--------------------------------------------------------------------
192 void BookCaseTask::markup(const Token &t)
193 {
194   ComplexTask::markup(t);
195
196   if (t.type() == START){
197
198     if(t.olaf() == OLAF::Bookcase){
199       if(f_base >= 0){
200         throw(Unexpected("second (illegal) BookCase element found"));
201       }
202       
203       f_base = t.level();
204     }
205
206     if(f_base >= 0){
207       switch(t.olaf()){
208         
209       case OLAF::BcName:
210         if(bookCaseName){
211           throw(Unexpected("second (illegal) bookcase name element found"));
212         }
213         
214         bookCaseName = new OL_Data(t, OLAF::OL_data);
215         addSubTask(bookCaseName);
216         break;
217
218       case OLAF::BcDesc:
219         if(bookCaseDesc){
220           throw(Unexpected("second (illegal) bookcase description element found"));
221         }
222         
223         bookCaseDesc = new OL_Data(t, OLAF::OL_data);
224         addSubTask(bookCaseDesc);
225         break;
226
227       }
228     
229       if(!f_style && t.LookupAttr(OLAF::OL_style)){
230         OL_Data *tmp_style = new OL_Data(t, OLAF::OL_style);
231         if ( tmp_style->DataWillBeAvailable() ) {
232           f_style = tmp_style;
233           addSubTask(f_style);
234         }
235         else {
236           delete tmp_style;
237         }
238       }
239     }
240   }
241
242   else if(t.type() == END){
243
244     if(t.level() == f_base){
245       const char *name;
246       const char *desc;
247       
248       if(bookCaseName){
249         name = bookCaseName->content();
250       }else{
251         throw(Unexpected("No bookcase name element in Bookcase element."));
252       }
253
254       if(bookCaseDesc){
255         desc = bookCaseDesc->content();
256       }else{
257         desc = "";
258       }
259       
260       printf("BookCase name: `%s' desc: `%s'\n", name, desc);
261     }
262
263     /* @# warn if no bookcase ever found? */
264   }
265 }
266
267
268 const char *
269 BookCaseTask::styleName()
270 {
271   const char *ret;
272
273   if ( Dispatch::RunTocGenOnly() ) {
274     return("");
275   }
276
277   if(!f_style) {
278     throw(Unexpected ("No style architectural form defined for bookcase."));
279   }
280
281   ret = f_style->content();
282
283 #ifdef FISH_DEBUG
284   DBUG_PRINT("Style", ("bookcase style is: %s", ret));
285 #endif
286   
287   if(!style->exist(ret)){
288 #ifdef FISH_DEBUG
289     DBUG_PRINT("Error", ("style `%s' not found", ret));
290 #endif
291     Token::signalError(Token::User, Token::Fatal, NULL, 0,
292                        "An undeclared style sheet name `%s' was found in the bookcase specification.\n", ret);
293   }
294   
295   return ret;
296 }
297     
298
299 /*****************
300  *
301  * BookTask
302  *
303  *****************/
304
305 BookTask::BookTask(BookCaseTask *bc)
306 {
307   f_base = 0;
308   f_seq_no = 1;
309
310   f_toc = NULL;
311   f_bookcase = bc;
312   
313   tocLocator = NULL;
314
315   shortTitle = NULL;
316   title = NULL;
317
318   tabName = NULL;
319   tabLocator = NULL;
320   
321   tabNames = new StringList();
322   tabLocators = new StringList();
323   tabLines = new StringList();
324   tabFiles = new StringList();
325   
326   f_node = new NodeTask(this, NULL);
327   addSubTask(f_node);
328
329   f_style = NULL;
330
331   e_string = NULL;
332   e_len    = 0;
333 }
334
335
336 BookTask::~BookTask()
337 {
338   KILLSUBTASK(f_node);
339
340   delete tabLocators;
341
342   KILLSUBTASK(title);
343   KILLSUBTASK(shortTitle);
344   KILLSUBTASK(tabName);
345   KILLSUBTASK(tabLocator);
346   
347 }
348
349 //------------------------------------------------------------------
350 void
351 BookTask::encrypt( const Token &t )
352 {
353   /*
354    * Grab all the strings that are required by the encryption API
355    */
356
357   char buf[ 256 ];
358
359 #ifdef LICENSE_MANAGEMENT
360   LTerms lt;
361
362   char *a_val;
363       
364   for ( const AttributeRec *arec = t.GetFirstAttr();
365         arec;
366         arec = t.GetNextAttr( arec ) ) {
367
368     a_val = ( char * )arec->getAttrValueString();
369     
370 #ifdef FISH_DEBUG
371     DBUG_PRINT("BookTasks", ("access attribute value %s", a_val) );
372 #endif
373         
374     switch ( arec->getAttrName() ) {
375       
376       case A_FEATURE :
377
378         if ( lt.add_feature( a_val ) != 0 ) {
379           throw(Unexpected("invalid access feature syntax"));
380         }
381         break;
382
383       case A_VEN_CODE :
384         if ( lt.add_ven_code( a_val ) != 0 ) {
385           throw(Unexpected("invalid access ven_code syntax") );
386         }
387         break;
388
389       case A_VERSION :
390         if ( lt.add_version( a_val ) !=  0 ) {
391           throw(Unexpected("invalid access version syntax"));
392         }
393         break;
394
395       case A_GROUPING :
396         if ( lt.add_grouping( a_val ) != 0 ) {
397           throw(Unexpected("invalid access grouping syntax"));
398         }
399         break;
400
401       case A_DEMO_TERMS :
402
403         if ( lt.add_demo_terms( a_val ) != 0 ) {
404           throw(Unexpected("invalid access demo_terms syntax"));
405         }
406         break;
407
408       case A_DEFAULT_SECTION :
409
410         if ( lt.add_noaccess_locator( a_val ) != 0 ) {
411           throw(Unexpected("invalid default section ID syntax"));
412         }
413         break;
414
415       }
416   }
417
418   if ( lt.pack( buf, 256 ) ) {
419     throw(Unexpected("Unable to pack the string for encryption"));
420   }
421
422   int len = 256;
423   if ( e_terms( &lt, buf, len ) ) {
424     throw(Unexpected("Unable to encrypt string for access control"));
425   }
426 #else
427   int len = 256;
428   (void) memset(buf, '\0', len);
429 #endif
430
431   e_string = (char *)malloc(len);
432   (void)memcpy(e_string, buf, len);     // Cannot use strdup - embedded NULs
433   e_len    = len;
434   
435 }
436
437 //----------------------------------------------------------------------
438 void BookTask::markup(const Token &t)
439 {
440   ComplexTask::markup(t);
441   
442   if(t.type() == START){
443     
444     if(t.olaf() == OLAF::Book){
445       if(f_base > 0){
446         throw(Unexpected("illegal nested BOOK architectural form"));
447       }
448
449       f_base = t.level();
450     }
451
452     if(f_base >= 0){
453       switch(t.olaf()){
454       case OLAF::BkSTitle:
455         if(shortTitle){
456           throw(Unexpected("BkSTitle already found"));
457         }
458
459         shortTitle = new OL_Data(t, OLAF::OL_data);
460         addSubTask(shortTitle);
461         break;
462
463       case OLAF::BkTitle:
464         if(title){
465           throw(Unexpected("BkTitle already found"));
466         }
467
468         title = new OL_Data(t, OLAF::OL_data);
469         addSubTask(title);
470         break;
471
472       case OLAF::Tab:
473         if(tabName){
474           tabNames->append(tabName->content());
475           tabLocators->append(tabLocator->content());
476           tabLines->append( form("%d", tabLocator->line_no()) );
477           tabFiles->append( tabLocator->filename() );
478           
479           KILLSUBTASK(tabName);
480           KILLSUBTASK(tabLocator);
481         }
482       
483         tabName = new OL_Data(t, OLAF::OL_data);
484         tabLocator = new OL_Data(t, OLAF::OL_idref, REMOVE_SPACES);
485         addSubTask(tabName);
486         addSubTask(tabLocator);
487         break;
488
489       case OLAF::BookAccess:
490         encrypt( t );
491         break;
492       }
493
494       if ( t.LookupAttr( OLAF::OL_ToC ) ) {
495         if ( f_toc ) {
496            throw(Unexpected("An illegal TOC was found.\n"));
497         }
498       
499         f_toc = new TOCTask(t, this);
500         addSubTask(f_toc);
501       }
502
503       if(f_base >= 0 && !f_style && t.LookupAttr(OLAF::OL_style)){
504         OL_Data *tmp_style = new OL_Data(t, OLAF::OL_style);
505         if ( tmp_style->DataWillBeAvailable() ) {
506           f_style = tmp_style;
507           addSubTask(f_style);
508         }
509         else {
510           delete tmp_style;
511         }
512       }
513     }
514   }
515
516   else if(t.type() == END){
517     if(t.level() == f_base){ /* found end of book... write out CCF data */
518       if ( !Dispatch::RunTocGenOnly() ) {
519         write_record();
520       }
521
522       reset();
523     }
524   }
525 }
526
527 //----------------------------------------------------------------------
528 void BookTask::write_record(void)
529 {
530   StringList tablines;
531
532   /* finish any pending tab */
533   if(tabName){
534     tabNames->append(tabName->content());
535     tabLocators->append(tabLocator->content());
536     tabLines->append( form("%d", tabLocator->line_no()) );
537     tabFiles->append(tabLocator->filename());
538   }
539       
540   for(unsigned int i = 0; i < tabNames->qty(); i++){
541     const char *name = tabNames->item(i);
542     const char *loc = tabLocators->item(i);
543     const char *line = tabLines->item(i);
544     const char *file = tabFiles->item(i);
545
546     int plen = strlen(name) + 1 + strlen(loc) + 1
547                             + strlen(line) + 1 + strlen(file) + 1;
548     char *p = new char [plen];
549
550     snprintf(p, plen, "%s\t%s\t%s\t%s", name, loc, line, file);
551     tablines.append(p);
552
553     delete [] p;
554   }
555
556   const char *bk_title;
557
558   if(title){
559     bk_title = title->content();
560   }else{
561     throw(Unexpected("Required Title form missing from Book"));
562   }
563     
564   const char *bk_stitle = bk_title;
565
566   if ( shortTitle ) {
567     bk_stitle = shortTitle->content();
568   }
569   
570   DBTable *tbl = bookcase()->table(BookCaseDB::BookMeta);
571
572   tbl->insert(STRING_CODE, locator(),
573                 STRING_CODE, bk_stitle,
574                 STRING_CODE, bk_title,
575                 INTEGER_CODE, f_seq_no,
576                 SHORT_LIST_CODE, tablines.qty(), STRING_CODE, tablines.array(),
577                 -STRING_CODE, e_string , (size_t)e_len,
578                 NULL);
579
580 #ifdef FISH_DEBUG
581   DBUG_PRINT("Book", ("Book... title: `%s' short title: `%s'\n",
582                       bk_title,
583                       bk_stitle));
584 #endif
585 }
586
587
588 void BookTask::reset()
589 {
590   KILLSUBTASK(shortTitle);
591   KILLSUBTASK(title);
592   KILLSUBTASK(f_toc);
593   KILLSUBTASK(f_style);
594  
595   delete tabNames; tabNames = new StringList();
596   delete tabLocators; tabLocators = new StringList();
597
598   tabName = tabLocator = NULL;
599
600   delete tabLines; tabLines = new StringList();
601   delete tabFiles; tabFiles = new StringList();
602
603   delete [] tocLocator; tocLocator = NULL;
604
605  
606   f_seq_no ++;
607   f_base = 0;
608
609 }
610
611
612 const char *BookTask::locator()
613 {
614
615   if ( Dispatch::RunTocGenOnly() ) {
616     return ("");
617   }
618
619   if(!tocLocator){
620     /* this is the first time anybody asked for the book's locator...
621      * it must be the TOC node asking for the book locator, which
622      * is the TOC node locator!
623      */
624     const char *l = f_node->locator();
625     int len = strlen(l);
626     tocLocator = new char[len + 1];
627     *((char *) memcpy(tocLocator, l, len) + len) = '\0';
628   }
629   
630   return tocLocator;
631 }
632
633
634 const char *
635 BookTask::styleName()
636 {
637   if ( Dispatch::RunTocGenOnly() ) {
638     return("");
639   }
640
641   const char *ret;
642   if(f_style){
643     ret = f_style->content();
644     
645     if(f_bookcase->styleTask()->exist(ret)){
646 #ifdef FISH_DEBUG
647       DBUG_PRINT("Style", ("book style is: %s", ret));
648 #endif
649     }else{
650       Token::signalError(Token::User, Token::Continuable, NULL, 0,
651                          "no such style `%s'\n", ret);
652       ret = f_bookcase->styleName();
653     }
654   }else{
655     ret = f_bookcase->styleName();
656   }
657
658   return ret;
659 }
660
661 //--------------------------------------------------------------
662 const char *
663 BookTask::book_title()
664 {
665   if ( !title ) {
666     throw(Unexpected("Book title is not available yet"));
667   }
668   
669   return( title->content() );
670 }
671
672 //--------------------------------------------------------------
673 const char *    
674 BookTask::book_short_title()
675 {
676   if ( !shortTitle ) { 
677     return( book_title() );
678   }
679
680   return( shortTitle->content() );
681 }
682