1 /*
2  * $Id: output.c,v 1.80.4.39 2008-07-19 17:56:42 opengl2772 Exp $
3  *
4  * Copyright (C) 1997-1999 Satoru Takabayashi All rights reserved.
5  * Copyright (C) 2000-2008 Namazu Project All rights reserved.
6  * This is free software with ABSOLUTELY NO WARRANTY.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  * 02111-1307, USA
22  *
23  *
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29 #ifdef HAVE_SUPPORT_H
30 #  include "support.h"
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 
38 #ifdef HAVE_ERRNO_H
39 #  include <errno.h>
40 #endif
41 
42 #ifdef HAVE_STRING_H
43 #  include <string.h>
44 #else
45 #  include <strings.h>
46 #endif
47 
48 #include "namazu.h"
49 #include "libnamazu.h"
50 #include "codeconv.h"
51 #include "output.h"
52 #include "util.h"
53 #include "field.h"
54 #include "search.h"
55 #include "result.h"
56 #include "i18n.h"
57 #include "message.h"
58 #include "form.h"
59 #include "var.h"
60 #include "idxname.h"
61 #include "query.h"
62 #include "system.h"
63 #include "charset.h"
64 
65 static int htmlmode    = 0;
66 static int cgimode     = 0;
67 static int quietmode   = 0;
68 
69 static int countmode   = 0;   /* like grep -c */
70 static int listmode    = 0;   /* like grep -l */
71 
72 static int allresult   = 0;   /* print all results */
73 static int pageindex   = 0;   /* print "Page: [1][2][3][4][5][6][7][8]" */
74 static int formprint   = 0;   /* print "<form> ... </form>" at cgimode */
75 static int refprint    = 0;   /* print "References:  [ foo: 123 ]" */
76 
77 static int maxresult   = 20;  /* max number of search results */
78 static int listwhence  = 0;   /* number which beginning of search results */
79 
80 static char template_suffix[BUFSIZE] = "normal"; /* suffix of NMZ.result.* */
81 
82 /*
83  * They are used for emphasizing keywords in html results.
84  */
85 static char emphasis_start_tag[BUFSIZE] = "<strong class=\"keyword\">";
86 static char emphasis_end_tag[BUFSIZE]   = "</strong>";
87 static char contenttype[BUFSIZE] = "text/html";
88 
89 /*
90  * Extern variables.
91  */
92 
93 extern NMZ_HANDLE handle_charset;
94 
95 /*
96  *
97  * Private functions
98  *
99  */
100 
101 static void emprint( char *s, int entity_encode );
102 static void unhtml_buffer( char *ostr );
103 static void fputs_without_html_tag ( const char *str, FILE *fp );
104 static char *load_nmz_result(const char *basedir);
105 static void print_hitnum_each ( struct nmz_hitnumlist *hn );
106 static int is_allresult ( void );
107 static int is_pageindex ( void );
108 static int is_countmode ( void );
109 static int is_listmode ( void );
110 static int is_quietmode ( void );
111 static int is_refprint ( void );
112 static int is_cgimode ( void );
113 static enum nmz_stat print_hlist ( NmzResult hlist );
114 static enum nmz_stat print_listing ( NmzResult hlist );
115 static void print_query ( const char * qs, int w );
116 static void print_page_index ( int n );
117 static void print_current_range ( int listmax );
118 static void print_hitnum_all_idx ( void );
119 static void print_hitnum ( int n );
120 static void print_msgfile ( const char *fname );
121 static void print_range ( NmzResult hlist );
122 static void print_errmsg(int errid);
123 
124 /*
125  * Print s to stdout with processing for emphasizing keyword
126  * and entity encoding.
127  */
128 static void
emprint(char * s,int entity_encode)129 emprint(char *s, int entity_encode)
130 {
131     int i;
132     int nestedtags = 0;
133     for (i = 0; i < BUFSIZE * 16 && *s; s++) {
134 	if (*s == EM_START_MARK) {
135             nestedtags++;
136 	    fputs(emphasis_start_tag, stdout);
137 	    continue;
138 	} else if (*s == EM_END_MARK) {
139             if (nestedtags > 0) nestedtags--;
140 	    fputs(emphasis_end_tag, stdout);
141 	    continue;
142 	}
143 	if (entity_encode) {
144 	    /* < > & " are converted to entities like &lt; */
145 	    if (*s == '<') {
146 		fputs("&lt;", stdout);
147 	    } else if (*s == '>') {
148 		fputs("&gt;", stdout);
149 	    } else if (*s == '&') {
150 		fputs("&amp;", stdout);
151 	    } else if (*s == '"') {
152 		fputs("&quot;", stdout);
153             } else if (*s == '\'') {
154                 fputs("&#39;", stdout);
155             } else if (*s == '(') {
156                 fputs("&#40;", stdout);
157             } else if (*s == ')') {
158                 fputs("&#41;", stdout);
159 	    } else {
160 		fputc(*s, stdout);
161 	    }
162 	} else {
163 	    fputc(*s, stdout);
164 	}
165     }
166     for (; nestedtags > 0; nestedtags--) {
167        fputs(emphasis_end_tag, stdout);
168     }
169 }
170 
171 /*
172  * Output string without HTML elements
173  */
174 static void
unhtml_buffer(char * ostr)175 unhtml_buffer(char *ostr) {
176     int f;
177     size_t i;
178     char buf[BUFSIZE] = "", *str;
179     size_t len;
180     len = strlen(ostr) + 1;
181     str = ostr;
182     for (f = 0, i = 0; i < BUFSIZE && *str; str++) {
183 
184 	/* Iso-2022-jp handling */
185 	if ((strncmp(str, "\033$", 2) == 0)
186 	    && (*(str + 2) == 'B' || *(str + 2) == '@'))
187 	{
188 	    char *p;
189 
190 	    strncpy(buf + i, str, 3);
191 	    i += 3;
192 	    str += 3;
193 	    p = strstr(str, "\033(");
194 	    if (p == NULL) {   /* non-terminating jis x 0208 */
195 		strcpy(buf + i, str);
196 		return;
197 	    }
198 	    if (*(p + 2) == 'J' || *(p + 2) == 'B' || *(p + 2) == 'H') {
199 		size_t len = p - str + 3;
200 		strncpy(buf + i, str, len);
201 		i += len;
202 		str += len;
203 	    } else {  /* unknown charset designation */
204 		strcpy(buf + i, str);
205 		return;
206 	    }
207 	}
208 
209         if (strncasecmp(str, "<br>", 4) == 0 && *(str + 4) != '\n') {
210             buf[i++] = '\n';
211             str += 3;
212             continue;
213         } else if (strncasecmp(str, "<br />", 6) == 0 && *(str + 6) != '\n') {
214             buf[i++] = '\n';
215             str += 5;
216             continue;
217         }
218 	if (*str == '<') {
219 	    f = 1;
220 	    continue;
221 	}
222 	if (*str == '>') {
223 	    f = 0;
224 	    continue;
225 	}
226 	if (f == 0) {
227 	    if (strncmp(str, "&lt;", strlen("&lt;")) == 0) {
228 		buf[i++] = '<';
229 		str += 3;
230 	    } else if (strncmp(str, "&gt;", strlen("&gt;")) == 0) {
231 		buf[i++] = '>';
232 		str += 3;
233 	    } else if (strncmp(str, "&amp;", strlen("&amp;")) == 0) {
234 		buf[i++] = '&';
235 		str += 4;
236 	    } else if (strncmp(str, "&quot;", strlen("&quot;")) == 0) {
237 		buf[i++] = '"';
238 		str += 5;
239 	    } else {
240 		buf[i++] = *str;
241 	    }
242 	}
243     }
244     buf[i] = '\0';
245     strncpy(ostr, buf, len);
246     ostr[len - 1] = '\0';
247 }
248 
249 static void
fputs_without_html_tag(const char * str,FILE * fp)250 fputs_without_html_tag(const char *str, FILE *fp)
251 {
252     char buf[BUFSIZE] = "";
253     strncpy(buf, str, BUFSIZE - 1);
254     unhtml_buffer(buf);
255     fputs(buf, fp);
256 }
257 
258 static void
print_hitnum_each(struct nmz_hitnumlist * hn)259 print_hitnum_each (struct nmz_hitnumlist *hn)
260 {
261     struct nmz_hitnumlist *hnptr = hn;
262 
263     if (hn->phrase != NULL) { /* it has phrases */
264 	hnptr = hn->phrase;
265         if (is_refprint() && !is_countmode() && !is_listmode() &&
266 	    !is_quietmode())
267 	{
268 	    printf(" { ");
269 	}
270     }
271 
272     if (is_refprint() && !is_countmode() &&
273 	!is_listmode() && !is_quietmode())
274     {
275 	do {
276 	    char *converted = nmz_query_external(hnptr->word);
277 	    if (converted == NULL) {
278 		die("print_hitnum_each");
279 	    }
280 
281 	    printf(" [ ");
282 	    html_print(converted);
283 	    free(converted);
284 
285 	    if (hnptr->stat == SUCCESS) {
286 		printf(": %d", hnptr->hitnum);
287 	    } else {
288 		char *errmsg = nmz_strerror(hnptr->stat);
289 		printf(" (%s) ", errmsg);
290 	    }
291 	    printf(" ] ");
292 	    hnptr = hnptr->next;
293 	} while (hn->phrase && hnptr != NULL);
294     }
295 
296     if (is_refprint() && !is_countmode() && !is_listmode() &&
297 	!is_quietmode() &&  hn->phrase != NULL) /* it has phrases */
298     {
299 	printf(" :: %d } ", hn->hitnum);
300     }
301 }
302 
303 static int
is_allresult(void)304 is_allresult(void)
305 {
306     return allresult;
307 }
308 
309 static int
is_pageindex(void)310 is_pageindex(void)
311 {
312     return pageindex;
313 }
314 
315 static int
is_countmode(void)316 is_countmode(void)
317 {
318     return countmode;
319 }
320 
321 static int
is_listmode(void)322 is_listmode(void)
323 {
324     return listmode;
325 }
326 
327 static int
is_quietmode(void)328 is_quietmode(void)
329 {
330     return quietmode;
331 }
332 
333 static int
is_refprint(void)334 is_refprint(void)
335 {
336     return refprint;
337 }
338 
339 static int
is_cgimode(void)340 is_cgimode(void)
341 {
342     return cgimode;
343 
344 }
345 
346 static char*
load_nmz_result(const char * basedir)347 load_nmz_result(const char *basedir)
348 {
349     char fname[BUFSIZE] = "", lang_suffix[BUFSIZE] = "", *buf;
350     char templatesuffix[BUFSIZE] = "";
351 
352     nmz_pathcat(basedir, NMZ.result);
353     strncpy(fname, NMZ.result, BUFSIZE - 1);
354     strncat(fname, ".", BUFSIZE - strlen(fname) - 1);
355     nmz_delete_since_path_delimitation(templatesuffix, get_templatesuffix(), BUFSIZE);
356     strncat(fname, templatesuffix, BUFSIZE - strlen(fname) - 1);  /* usually "normal" */
357 
358     if (nmz_choose_msgfile_suffix(fname, lang_suffix) != SUCCESS) {
359 	nmz_warn_printf("%s: %s", fname, strerror(errno));
360 	return NULL;
361     }
362     strncat(fname, lang_suffix, BUFSIZE - strlen(fname) - 1);
363 
364     /* buf is allocated in nmz_readfile. */
365     buf = nmz_readfile(fname);
366     if (buf == NULL) { /* failed */
367 	return NULL;
368     }
369 
370     return buf;
371 }
372 
373 /*
374  * Display one searched document according to NMZ.result.* file.
375  * e.g.,
376  *
377  *   <dt>1. <strong><a href="/foo/gunzip.1.gz">GZIP(1)</a></strong> (score: xx)
378  *   <dd><strong>Author</strong>: <em>(unknown)</em>
379  *   <dd><strong>Date</strong>: <em>Thu, 09 Apr 1998 12:59:59</em>
380  *   <dd>gzip, gunzip, zcat - compress or expand files:: Gzip
381  *   reduces the size of the named files using Lempel-Ziv
382  *   coding (LZ77). Whenever possible, each file is replaced
383  *   by one with the extension .gz, while
384  *   <dd><a href="/foo/gunzip.1.gz">/foo/gunzip.1.gz</a> (5,410 bytes)<br><br>
385  */
386 static enum nmz_stat
print_hlist(NmzResult hlist)387 print_hlist(NmzResult hlist)
388 {
389     int i;
390     char *the_template = NULL;    /* User-specified  template. */
391     char *template_caches[INDEX_MAX];   /* For caching each NMZ.result */
392 
393     if (hlist.num <= 0 || get_maxresult() == 0) {
394 	return SUCCESS; /* No document searched but success. */
395     }
396 
397     /*
398      * Clear pointers for caching NMZ.result.
399      */
400     for (i = 0; i < nmz_get_idxnum(); i++) {
401 	template_caches[i] = NULL;
402     }
403 
404     /*
405      * Check whether user-specified templatedir is set or not.
406      */
407     {
408 	char templdir[BUFSIZE];
409 	strcpy(templdir, get_templatedir());
410 	if (*templdir != '\0') { /* user-specified one is set. */
411 	    the_template = load_nmz_result(templdir);
412 	    if (the_template == NULL) {
413 		return ERR_CANNOT_OPEN_RESULT_FORMAT_FILE;
414 	    }
415 	}
416     }
417 
418     for (i = get_listwhence(); i < hlist.num; i++) {
419 	/*
420 	 * Prepare large memory for replace_field() for safety.
421 	 * FIXME: static memory allocation may cause buffer overflow.
422 	 */
423 	char result[BUFSIZE * 128] = "";
424 	int counter;
425 	char *template = the_template;
426 
427 	counter = i + 1;
428 
429 	if (!is_allresult() && (i >= get_listwhence() + get_maxresult()))
430 	    break;
431 
432 	if (is_listmode()) {
433 	    template = "${uri}";
434 	} else {
435 	    int idxid = hlist.data[i].idxid;
436 	    /*
437 	     * If user-specified templatedir is not set. and
438 	     */
439 	    if (template == NULL) {
440 		/*
441 		 * If NMZ.result is not cached, load NMZ.result and cache it in
442 		 * template_caches[].
443 		 */
444 		if (template_caches[idxid] == NULL) {
445 		    char *basedir = nmz_get_idxname(idxid);
446 		    template_caches[idxid] = load_nmz_result(basedir);
447 		    if (template_caches[idxid] == NULL) {
448 			return ERR_CANNOT_OPEN_RESULT_FORMAT_FILE;
449 		    }
450 		}
451 		template = template_caches[idxid];
452 	    }
453 	}
454 
455 	if (is_htmlmode() || is_listmode()) {
456 	    compose_result(hlist.data[i], counter, template,  result);
457 	} else {
458 	    char tmpbuf[BUFSIZE] = "";
459 	    strncpy(tmpbuf, template, BUFSIZE -1);
460 	    tmpbuf[BUFSIZE - 1] = 0;
461 	    unhtml_buffer(tmpbuf);
462 	    compose_result(hlist.data[i], counter, tmpbuf,  result);
463 	}
464 	{
465 	    char *converted = nmz_codeconv_external(result);
466 	    if (converted == NULL) {
467 		die(nmz_get_dyingmsg());
468 	    }
469 	    if (is_htmlmode() || is_listmode()) {
470 		html_print(converted);
471 	    } else {
472 		puts(converted+1); /* remove '\t' in the head of buffer */
473 	    }
474 	    free(converted);
475 	    printf("\n");
476 	}
477     }
478 
479     /* Free user-specified template. */
480     if (the_template != NULL) {
481 	free(the_template);
482     }
483 
484     /* Free all template_caches[] */
485     for (i = 0; i < nmz_get_idxnum(); i++) {
486 	if (template_caches[i] != NULL) {
487 	    free(template_caches[i]);
488 	}
489     }
490 
491     return SUCCESS;
492 }
493 
494 static enum nmz_stat
print_listing(NmzResult hlist)495 print_listing(NmzResult hlist)
496 {
497     enum nmz_stat ret;
498 
499     if (is_htmlmode()) {
500         printf("<dl>\n");
501     }
502 
503     ret = print_hlist(hlist);
504     if (ret != SUCCESS) {
505 	return ret;
506     }
507 
508     if (is_htmlmode()) {
509         printf("</dl>\n");
510     }
511     return SUCCESS;
512 }
513 
514 /*
515  * For page_index().
516  */
517 static void
print_query(const char * qs,int w)518 print_query(const char * qs, int w)
519 {
520     int foo = 0;
521     while (*qs) {
522 	if (strncmp(qs, "whence=", strlen("whence=")) == 0) {
523 	    foo = 1;
524 	    printf("whence=%d", w);
525 	    for (qs += strlen("whence="); nmz_isdigit((unsigned char)*qs); qs++);
526 	} else {
527 	    /* '"' is converted to entities "&quot;" */
528 	    putc_entitize(*qs);
529 	    qs++;
530 	}
531     }
532     if (foo == 0) {
533 	printf("&amp;whence=%d", w);
534     }
535 }
536 
537 /*
538  * Display page index.
539  */
540 static void
print_page_index(int n)541 print_page_index(int n)
542 {
543     int i, max, whence;
544     char *qs; /* QUERY_STRING */
545     char *sn; /* SCRIPT_NAME  */
546     char *dn; /* DOCUMENT_URI  */
547 
548     qs = nmz_getenv("QUERY_STRING");
549     sn = nmz_getenv("SCRIPT_NAME");
550     dn = nmz_getenv("DOCUMENT_URI");
551 
552     if(dn == NULL || *dn == '\0') {
553         dn = sn;
554     } else {
555 	/* Delete characters after '?' for Lotus Domino Server R5.06a */
556 	char *s;
557 	for (s = dn; *s; s++)
558 	    if (*s == '?') {*s = 0; break;}
559     }
560 
561     html_print(_("	<strong>Page:</strong> "));
562 
563     max    = get_maxresult();
564     whence = get_listwhence();
565     for (i = 0; i < PAGE_MAX; i++) {
566 	if (i * max >= n)
567 	    break;
568 	if (is_htmlmode()) {
569 	    if (i * max != whence) {
570 		printf("<a href=\"");
571 		fputs(dn, stdout);
572 		fputc('?', stdout);
573 		print_query(qs, i * max);
574 		printf("\">");
575 	    } else {
576 		printf("<strong>");
577 	    }
578 	}
579 	printf("[%d]", i + 1);
580 	if (is_htmlmode()) {
581 	    if (i * max != whence) {
582 		printf("</a> ");
583 	    } else
584 		printf("</strong> ");
585 	}
586 	if (is_allresult()) {
587 	    break;
588 	}
589     }
590 }
591 
592 /*
593  * Output current range
594  */
595 static void
print_current_range(int listmax)596 print_current_range(int listmax)
597 {
598     int max, whence;
599 
600     max    = get_maxresult();
601     whence = get_listwhence();
602 
603     if (is_htmlmode()) {
604 	printf("<strong>");
605     }
606     printf(_("Current List: %d"), whence + 1);
607 
608     printf(" - ");
609     if (!is_allresult() && ((whence + max) < listmax)) {
610 	printf("%d", whence + max);
611     } else {
612 	printf("%d", listmax);
613     }
614     if (is_htmlmode()) {
615 	printf("</strong><br>\n");
616     } else {
617 	fputc('\n', stdout);
618     }
619 }
620 
621 static void
print_hitnum_all_idx(void)622 print_hitnum_all_idx(void)
623 {
624     int idxid;
625     for (idxid = 0; idxid < nmz_get_idxnum(); idxid ++) {
626         struct nmz_hitnumlist *hnlist = nmz_get_idx_hitnumlist(idxid);
627 
628 	if (is_refprint() && !is_countmode() &&
629 	    !is_listmode() && !is_quietmode())
630 	{
631 	    if (nmz_get_idxnum() > 1) {
632 	        if (is_htmlmode()) {
633 		    char *idxname = nmz_get_idxname(idxid);
634 		    if (is_cgimode()) {
635 			/* For hiding a full pathname of an index */
636 			idxname =  nmz_get_idxname(idxid)
637 			    + strlen(nmz_get_defaultidx()) + 1;
638 		    }
639 		    printf("<li><strong>");
640 		    puts_entitize(idxname);
641 		    printf("</strong>: ");
642 		} else {
643 		    printf("(%s)", nmz_get_idxname(idxid));
644 		}
645 	    }
646 	}
647 
648         while (hnlist != NULL) {
649 	    print_hitnum_each(hnlist);
650 	    hnlist = hnlist->next;
651 	}
652 
653 	if (is_refprint() && !is_countmode() && !is_listmode() &&
654 	    !is_quietmode()) {
655 	    if (nmz_get_idxnum() > 1 && nmz_get_querytokennum() > 1) {
656 	        printf(_(" [ TOTAL: %d ]"), nmz_get_idx_totalhitnum(idxid));
657 	    }
658             if (nmz_get_idxnum() > 1) {
659                 if (is_htmlmode()) {
660                    printf("</li>");
661                 }
662             }
663 	    printf("\n");
664 	}
665     }
666 }
667 
668 static void
print_hitnum(int n)669 print_hitnum(int n)
670 {
671     html_print(_("	<p><strong> Total "));
672     if (is_htmlmode()) {
673         printf("<!-- HIT -->%d<!-- HIT -->", n);
674     }
675     else {
676         printf("%d", n);
677     }
678     html_print(_("	 documents matching your query.</strong></p>\n\n"));
679 }
680 
681 /*
682  * Output contents of a message file such as NMZ.tips or NMZ.body.
683  */
684 static void
print_msgfile(const char * fname)685 print_msgfile(const char *fname) {
686     char suffix[BUFSIZE] = "", tmpfname[BUFSIZE] = "";
687 
688     if (nmz_choose_msgfile_suffix(fname, suffix) == SUCCESS) {
689 	char *buf;
690 
691 	strncpy(tmpfname, fname, BUFSIZE - 1);
692 	strncat(tmpfname, suffix, BUFSIZE - strlen(tmpfname) - 1);
693 
694 	buf = nmz_readfile(tmpfname); /* buf is allocated in nmz_readfile. */
695 	if (buf == NULL) {
696 	    die(nmz_get_dyingmsg());
697 	}
698 	/* In case of suffix isn't equal to lang, we need code conversion */
699 	if (strcmp(suffix, nmz_get_lang()) != 0) {
700             /* new is allocated in nmz_codeconv_external. */
701 	    char *new = nmz_codeconv_external(buf);
702 	    free(buf);  /* Then we should free buf's memory */
703 	    buf = new;
704 	}
705 
706 	fputs(buf, stdout);
707 	free(buf);
708     } else {
709 	nmz_warn_printf("%s: %s", fname, strerror(errno));
710     }
711 }
712 
713 static void
print_range(NmzResult hlist)714 print_range(NmzResult hlist)
715 {
716     if (is_htmlmode()) {
717         printf("<div class=\"namazu-result-footer\">\n");
718     }
719     print_current_range(hlist.num);
720     if (is_pageindex()) {
721         print_page_index(hlist.num);
722     }
723     if (is_htmlmode()) {
724         printf("</div>\n");  /* class="namazu-result-footer" */
725     } else {
726         printf("\n");
727     }
728 }
729 
730 /*
731  * Print the error message specified by errid while outputing the results.
732  */
733 static void
print_errmsg(int errid)734 print_errmsg(int errid)
735 {
736     char *errmsg = nmz_strerror(errid);
737     char buf[BUFSIZE] = "";
738     snprintf(buf, BUFSIZE - 1, _("	<h2>Error!</h2>\n<p>%s</p>\n"), errmsg);
739     html_print(buf);
740 }
741 
742 /*
743  *
744  * Public functions
745  *
746  */
747 enum nmz_stat
print_result(NmzResult hlist,const char * query,const char * subquery)748 print_result(NmzResult hlist, const char *query, const char *subquery)
749 {
750     if (is_htmlmode()) {
751         if (is_cgimode()) {
752             printf("%s %s" CRLF CRLF, MSG_MIME_HEADER, get_contenttype());
753         }
754 	print_headfoot(NMZ.head, query, subquery);
755     }
756 
757     if (hlist.stat != SUCCESS) {
758 	print_errmsg(hlist.stat);
759 	return FAILURE;
760     }
761 
762     if (!is_countmode() && !is_listmode() && !is_quietmode()) {
763         if (is_htmlmode()) {
764             fputs("<div class=\"namazu-result-header\">\n", stdout);
765         }
766     }
767 
768     /* Result1:  <h2>Results:</h2>, References:  */
769     if (is_refprint() && !is_countmode() &&
770 	!is_listmode() && !is_quietmode())
771     {
772 	html_print(_("	<h2>Results:</h2>\n"));
773 
774 	if (is_htmlmode()) {
775 	    fputs("<p>\n", stdout);
776 	} else {
777 	    fputc('\n', stdout);
778 	}
779 	printf(_("References: "));
780 	if (nmz_get_idxnum() > 1 && is_htmlmode()) {
781 	    fputs("</p>\n", stdout);
782 	}
783 
784         if (nmz_get_idxnum() > 1) {
785             printf("\n");
786             if (is_htmlmode())
787                 printf("<ul>\n");
788         }
789     }
790 
791     print_hitnum_all_idx(); /* print hit numbers for all index. */
792 
793     if (is_refprint() && !is_countmode() &&
794 	!is_listmode() && !is_quietmode()) {
795         if (nmz_get_idxnum() > 1 && is_htmlmode()) {
796             printf("</ul>\n");
797         }
798 	if (nmz_get_idxnum() == 1 && is_htmlmode()) {
799 	    printf("\n</p>\n");
800 	} else {
801 	    fputc('\n', stdout);
802 	}
803     }
804 
805     if (hlist.num > 0) {
806         if (!is_countmode() && !is_listmode() && !is_quietmode()) {
807             print_hitnum(hlist.num);  /* <!-- HIT -->%d<!-- HIT --> */
808             if (is_htmlmode()) {
809                 fputs("</div>\n", stdout); /* class="namazu-result-header" */
810             }
811         }
812 	if (is_countmode()) {
813 	    printf("%d\n", hlist.num);
814 	} else {
815 	    enum nmz_stat ret = print_listing(hlist);
816 
817 	    if (ret != SUCCESS) { /* summary listing */
818 		print_errmsg(ret);
819 		return ret;
820 	    }
821 	}
822         if (!is_countmode() && !is_listmode() && !is_quietmode()) {
823             print_range(hlist);
824         }
825     } else {
826         if (is_countmode()) {
827             printf("0\n");
828         } else if (!is_listmode() && !is_quietmode()) {
829 	    html_print(_("	<p>No document matching your query.</p>\n"));
830 	    if (is_htmlmode()) {
831                 fputs("</div>\n", stdout); /* class="namazu-result-header" */
832 		print_msgfile(NMZ.tips);
833 	    }
834         }
835     }
836 
837     if (is_htmlmode()) {
838 	print_headfoot(NMZ.foot, query, subquery);
839     }
840 
841     return SUCCESS;
842 }
843 
844 /*
845  * Print default page: NMZ.{head,body,foot}
846  */
847 void
print_default_page(void)848 print_default_page (void) {
849     if (is_htmlmode()) {
850         if (is_cgimode()) {
851 	    printf("%s %s" CRLF CRLF, MSG_MIME_HEADER, get_contenttype());
852         }
853 	print_headfoot(NMZ.head, "", "");
854 	print_msgfile(NMZ.body);
855 	print_headfoot(NMZ.foot, "", "");
856     }
857 }
858 
859 /*
860  * output string as non-html (replace special characters by entities)
861  */
862 void
puts_entitize(const char * str)863 puts_entitize(const char *str)
864 {
865     const char *p = str;
866     for (; *p != 0; p++) {
867 	putc_entitize(*p);
868     }
869 }
870 
871 void
putc_entitize(int c)872 putc_entitize(int c)
873 {
874 	if (c == '<') {
875 	    fputs("&lt;", stdout);
876 	} else if (c == '>') {
877 	    fputs("&gt;", stdout);
878 	} else if (c == '&') {
879 	    fputs("&amp;", stdout);
880 	} else if (c == '"') {
881 	    fputs("&quot;", stdout);
882         } else if (c == '\'') {
883             /* not support &apos; for HTML 4.01 */
884             /* fputs("&apos;", stdout); */
885             fputs("&#39;", stdout);
886         } else if (c == '(') {
887             fputs("&#40;", stdout);
888         } else if (c == ')') {
889             fputs("&#41;", stdout);
890 	} else {
891 	    fputc(c, stdout);
892 	}
893 }
894 
895 void
set_emphasis_tags(const char * start_tag,const char * end_tag)896 set_emphasis_tags(const char *start_tag, const char *end_tag)
897 {
898     strncpy(emphasis_start_tag, start_tag, BUFSIZE - 1);
899     strncpy(emphasis_end_tag,   end_tag, BUFSIZE - 1);
900 }
901 
902 char *
get_emphasis_tag_start(void)903 get_emphasis_tag_start(void)
904 {
905     return emphasis_start_tag;
906 }
907 
908 char *
get_emphasis_tag_end(void)909 get_emphasis_tag_end(void)
910 {
911     return emphasis_end_tag;
912 }
913 
914 void
set_contenttype(const char * str)915 set_contenttype(const char *str)
916 {
917     strncpy(contenttype, str, BUFSIZE - 1);
918 }
919 
920 char *
get_contenttype(void)921 get_contenttype(void)
922 {
923     static char buff[BUFSIZE];
924     char *p;
925     int is_charset = 0;
926 
927 
928     buff[0] = '\0';
929     p = strtok(contenttype, " \t\n\r;");
930     while(p) {
931         if (!strncasecmp(p, "charset=", strlen("charset="))) {
932             is_charset = 1;
933             break;
934         }
935         p = strtok(NULL, " \t\n\r;");
936     }
937 
938     if (!is_charset) {
939         char *charset = "ISO-8859-1";
940         int cont = 1;
941         char suffix[BUFSIZE] = "";
942         char *lang;
943 
944         buff[0] = '\0';
945         if (nmz_choose_msgfile_suffix(NMZ.head, suffix) == SUCCESS) {
946             if (suffix[0] == '.') {
947                 strncpy(buff, suffix + 1, BUFSIZE - 1);
948             } else {
949                 buff[0] = '\0';
950             }
951         }
952         lang = nmz_get_lang();
953         if (!strncasecmp(lang, "ja", 2)) {
954             if (!strcasecmp(lang, "ja_JP.SJIS")) {
955                 /* Shift_JIS */
956                 strncpy(buff, "ja_JP.SJIS", BUFSIZE - 1);
957             } else if (!strcasecmp(lang, "ja_JP.ISO-2022-JP")) {
958                 /* ISO-2022-JP */
959                 strncpy(buff, "ja_JP.ISO-2022-JP", BUFSIZE - 1);
960             } else {
961                 /* EUC-JP */
962                 strncpy(buff, "ja", BUFSIZE - 1);
963             }
964         }
965 
966         while(cont == 1) {
967             int i;
968             char *value;
969             cont = 0;
970 
971             if ((value = nmz_find_first_strlist(handle_charset, buff))) {
972                 charset = value;
973                 break;
974             }
975 
976             for(i = (int)strlen(buff) - 1; i >= 0; i--) {
977                 if (buff[i] == '.' || buff[i] == '_' || buff[i] == '@') {
978                     buff[i] = '\0';
979                     cont = 1;
980                     break;
981                 }
982             }
983         }
984 
985         sprintf(buff, "%s; charset=%s", contenttype, charset);
986         return(buff);
987     }
988 
989     return(contenttype);
990 }
991 
992 void
set_htmlmode(int mode)993 set_htmlmode(int mode)
994 {
995     htmlmode = mode;
996 }
997 
998 int
is_htmlmode(void)999 is_htmlmode(void)
1000 {
1001     return htmlmode;
1002 }
1003 
1004 void
set_cgimode(int mode)1005 set_cgimode(int mode)
1006 {
1007     cgimode = mode;
1008 }
1009 
1010 void
set_quietmode(int mode)1011 set_quietmode(int mode)
1012 {
1013     quietmode = mode;
1014 }
1015 
1016 void
set_countmode(int mode)1017 set_countmode(int mode)
1018 {
1019     countmode = mode;
1020 }
1021 
1022 void
set_listmode(int mode)1023 set_listmode(int mode)
1024 {
1025     listmode = mode;
1026 }
1027 
1028 void
set_allresult(int mode)1029 set_allresult(int mode)
1030 {
1031     allresult = mode;
1032 }
1033 
1034 void
set_pageindex(int mode)1035 set_pageindex(int mode)
1036 {
1037     pageindex = mode;
1038 }
1039 
1040 void
set_formprint(int mode)1041 set_formprint(int mode)
1042 {
1043     formprint = mode;
1044 }
1045 
1046 int
is_formprint(void)1047 is_formprint(void)
1048 {
1049     return formprint;
1050 }
1051 
1052 void
set_refprint(int mode)1053 set_refprint(int mode)
1054 {
1055     refprint = mode;
1056 }
1057 
1058 void
set_maxresult(int num)1059 set_maxresult(int num)
1060 {
1061     maxresult = num;
1062 }
1063 
1064 int
get_maxresult(void)1065 get_maxresult(void)
1066 {
1067     return maxresult;
1068 }
1069 
1070 void
set_listwhence(int num)1071 set_listwhence(int num)
1072 {
1073     listwhence = num;
1074 }
1075 
1076 int
get_listwhence(void)1077 get_listwhence(void)
1078 {
1079     return listwhence;
1080 }
1081 
1082 
1083 void
set_templatesuffix(const char * tmpl)1084 set_templatesuffix(const char *tmpl)
1085 {
1086     int i = 0;
1087     char *p;
1088 
1089     strncpy(template_suffix, tmpl, BUFSIZE - 1);
1090     template_suffix[BUFSIZE - 1] = '\0';
1091 
1092     /*
1093      *   result : [A-Za-z][A-Za-z0-9_\-]*
1094      *   (ex. normal, short)
1095      */
1096     p = template_suffix;
1097     while(*p) {
1098         if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
1099         (((*p >= '0' && *p <= '9') || *p == '_' || *p == '-')&& i != 0))) {
1100             *p = '\0';
1101             break;
1102         }
1103         p++;
1104         i++;
1105     }
1106 
1107     if (template_suffix[0] == '\0') {
1108         strncpy(template_suffix, "normal", BUFSIZE - 1);
1109         template_suffix[BUFSIZE - 1] = '\0';
1110     }
1111 }
1112 
1113 char *
get_templatesuffix(void)1114 get_templatesuffix(void)
1115 {
1116     return template_suffix;
1117 }
1118 
1119 
1120 /*
1121  * Namazu version fputs, it works with considereation of html mode.
1122  */
1123 void
html_print(const char * str)1124 html_print(const char *str)
1125 {
1126     char buf[BUFSIZE * 16] = "";
1127     int is_nmz_html = 0;
1128 
1129     if ((int)*str == (int)'\t') { /* Namazu's HTML message */
1130         is_nmz_html = 1;
1131     }
1132 
1133     strcpy(buf, str + is_nmz_html);
1134     if (is_htmlmode()) {
1135         /*
1136 	 * If str is Namazu's HTML message, it will be printed with emprint.
1137 	 * If not, it will be printed with entity conversion
1138 	 */
1139         emprint(buf, ! is_nmz_html);
1140     } else {
1141         /*
1142 	 * If str is Namazu's HTML message, it will be printed without
1143 	 * HTML tag, if not, it will be printed as is
1144 	 */
1145         if (is_nmz_html) {
1146             fputs_without_html_tag(buf, stdout);
1147         }
1148 	else {
1149             fputs(buf, stdout);
1150         }
1151     }
1152 }
1153 
1154 
1155 /*
1156  * Print the error message and die.
1157  */
1158 void
die(const char * fmt,...)1159 die(const char *fmt, ...)
1160 {
1161     va_list args;
1162 
1163     fflush(stdout);
1164     fflush(stderr);
1165 
1166     if (is_htmlmode()) {
1167         static char msg[BUFSIZE] = "";
1168 
1169         va_start(args, fmt);
1170         vsnprintf(msg, BUFSIZE - 1, fmt, args);
1171         va_end(args);
1172 
1173         if (is_cgimode()) {
1174             printf("%s %s; %s" CRLF CRLF, MSG_MIME_HEADER,
1175                 "text/html", _("charset=ISO-8859-1"));
1176         }
1177         printf("<html><body>\n");
1178         printf(_("<h2>Error</h2>\n<p>"));
1179         puts_entitize(msg);
1180         printf(_("</p>"));
1181         printf("\n</body></html>\n");
1182     } else {
1183 	fprintf(stderr, "%s: ", PACKAGE);
1184 	va_start(args, fmt);
1185 	vfprintf(stderr, fmt, args);
1186 	va_end(args);
1187         if (fmt[strlen(fmt) - 1] != '\n') {
1188             fprintf(stderr, "\n");
1189         }
1190     }
1191 
1192     exit_nmz(EXIT_FAILURE);
1193 }
1194 
1195