about summary refs log tree commit diff stats
path: root/draw.c
blob: b8b6c1db6378ff145693506edfb6bfd76f445142 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */
#include "dwm.h"
#include <stdio.h>
#include <string.h>
#include <X11/Xlocale.h>

/* static */

static unsigned int
textnw(const char *text, unsigned int len)
{
	XRectangle r;

	if(dc.font.set) {
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
		return r.width;
	}
	return XTextWidth(dc.font.xfont, text, len);
}

static void
drawtext(const char *text, unsigned long col[ColLast], Bool highlight)
{
	int x, y, w, h;
	static char buf[256];
	unsigned int len, olen;
	XGCValues gcv;
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };

	XSetForeground(dpy, dc.gc, col[ColBG]);
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);

	if(!text)
		return;

	w = 0;
	olen = len = strlen(text);
	if(len >= sizeof(buf))
		len = sizeof(buf) - 1;
	memcpy(buf, text, len);
	buf[len] = 0;

	h = dc.font.ascent + dc.font.descent;
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
	x = dc.x + (h / 2);

	/* shorten text if necessary */
	while(len && (w = textnw(buf, len)) > dc.w - h)
		buf[--len] = 0;
	if(len < olen) {
		if(len > 1)
			buf[len - 1] = '.';
		if(len > 2)
			buf[len - 2] = '.';
		if(len > 3)
			buf[len - 3] = '.';
	}

	if(w > dc.w)
		return; /* too long */
	gcv.foreground = col[ColFG];
	if(dc.font.set) {
		XChangeGC(dpy, dc.gc, GCForeground, &gcv);
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
	}
	else {
		gcv.font = dc.font.xfont->fid;
		XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
	}
	if(highlight) {
		r.x = dc.x + 2;
		r.y = dc.y + 2;
		r.width = r.height = 3;
		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
	}
}

/* extern */

void
drawall()
{
	Client *c;

	for(c = clients; c; c = getnext(c->next))
		drawtitle(c);
	drawstatus();
}

void
drawstatus()
{
	int i, x;

	dc.x = dc.y = 0;

	for(i = 0; i < ntags; i++) {
		dc.w = textw(tags[i]);
		if(seltag[i])
			drawtext(tags[i], dc.sel, sel && sel->tags[i]);
		else
			drawtext(tags[i], dc.norm, sel && sel->tags[i]);
		dc.x += dc.w;
	}

	dc.w = bmw;
	drawtext(arrange == dotile ? TILESYMBOL : FLOATSYMBOL, dc.status, False);

	x = dc.x + dc.w;
	dc.w = textw(stext);
	dc.x = bx + bw - dc.w;
	if(dc.x < x) {
		dc.x = x;
		dc.w = bw - x;
	}
	drawtext(stext, dc.status, False);

	if((dc.w = dc.x - x) > bh) {
		dc.x = x;
		if(sel)
			drawtext(sel->name, dc.sel, False);
		else
			drawtext(NULL, dc.norm, False);
	}
	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
	XSync(dpy, False);
}

void
drawtitle(Client *c)
{
	if(c == sel && issel) {
		drawstatus();
		XUnmapWindow(dpy, c->twin);
		XSetWindowBorder(dpy, c->win, dc.sel[ColBG]);
		return;
	}

	XSetWindowBorder(dpy, c->win, dc.norm[ColBG]);
	XMapWindow(dpy, c->twin);
	dc.x = dc.y = 0;
	dc.w = c->tw;
	drawtext(c->name, dc.norm, False);
	XCopyArea(dpy, dc.drawable, c->twin, dc.gc, 0, 0, c->tw, c->th, 0, 0);
	XSync(dpy, False);
}

unsigned long
getcolor(const char *colstr)
{
	Colormap cmap = DefaultColormap(dpy, screen);
	XColor color;

	XAllocNamedColor(dpy, cmap, colstr, &color, &color);
	return color.pixel;
}

void
setfont(const char *fontstr)
{
	char **missing, *def;
	int i, n;

	missing = NULL;
	setlocale(LC_ALL, "");
	if(dc.font.set)
		XFreeFontSet(dpy, dc.font.set);
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
	if(missing) {
		while(n--)
			fprintf(stderr, "missing fontset: %s\n", missing[n]);
		XFreeStringList(missing);
		if(dc.font.set) {
			XFreeFontSet(dpy, dc.font.set);
			dc.font.set = NULL;
		}
	}
	if(dc.font.set) {
		XFontSetExtents *font_extents;
		XFontStruct **xfonts;
		char **font_names;

		dc.font.ascent = dc.font.descent = 0;
		font_extents = XExtentsOfFontSet(dc.font.set);
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
			if(dc.font.ascent < (*xfonts)->ascent)
				dc.font.ascent = (*xfonts)->ascent;
			if(dc.font.descent < (*xfonts)->descent)
				dc.font.descent = (*xfonts)->descent;
			xfonts++;
		}
	}
	else {
		if(dc.font.xfont)
			XFreeFont(dpy, dc.font.xfont);
		dc.font.xfont = NULL;
		dc.font.xfont = XLoadQueryFont(dpy, fontstr);
		if (!dc.font.xfont)
			dc.font.xfont = XLoadQueryFont(dpy, "fixed");
		if (!dc.font.xfont)
			eprint("error, cannot init 'fixed' font\n");
		dc.font.ascent = dc.font.xfont->ascent;
		dc.font.descent = dc.font.xfont->descent;
	}
	dc.font.height = dc.font.ascent + dc.font.descent;
}

unsigned int
textw(const char *text)
{
	return textnw(text, strlen(text)) + dc.font.height;
}
span> * W WW Address mapping convention: * * /servername/database/type/length/document-id * * /servername/database?word+word+word */ /* WIDE AREA INFORMATION SERVER SOFTWARE: No guarantees or restrictions. See the readme file for the full standard disclaimer. Brewster@think.com */ #include <HTUtils.h> #include <HTParse.h> #include <HTAccess.h> /* We implement a protocol */ #include <HTML.h> /* The object we will generate */ #include <HTWSRC.h> #include <HTTCP.h> #include <HTCJK.h> #include <HTAlert.h> #include <LYStrings.h> #undef lines /* term.h conflict with wais.h */ #undef alloca /* alloca.h conflict with wais.h */ /* From WAIS * --------- */ #ifdef VMS #include <HTVMS_WaisUI.h> #include <HTVMS_WaisProt.h> #elif defined(HAVE_WAIS_H) #include <wais.h> #else #include <ui.h> #endif /* VMS */ #define MAX_MESSAGE_LEN 100000 #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */ #define WAISSEARCH_DATE "Fri Jul 19 1991" /* FROM WWW * -------- */ #include <LYUtils.h> #include <LYLeaks.h> #define DIRECTORY "/cnidr.org:210/directory-of-servers" /* #define DIRECTORY "/quake.think.com:210/directory-of-servers" */ #define BIG 1024 /* identifier size limit @@@@@ */ #define BUFFER_SIZE 4096 /* Arbitrary size for efficiency */ #define HEX_ESCAPE '%' static BOOL as_gate; /* Client is using us as gateway */ static char line[2048]; /* For building strings to display */ /* Must be able to take id */ #define PUTC(c) (*target->isa->put_character)(target, c) #define PUTS(s) (*target->isa->put_string)(target, s) #define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0) #define END(e) (*target->isa->end_element)(target, e, 0) #define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ (*target->isa->end_element)(target, e, 0) #define FREE_TARGET (*target->isa->_free)(target) struct _HTStructured { const HTStructuredClass *isa; /* ... */ }; /* ------------------------------------------------------------------------ */ /* ---------------- Local copy of connect_to_server calls ----------------- */ /* ------------------------------------------------------------------------ */ /* Returns 1 on success, 0 on fail, -1 on interrupt. */ static int fd_mosaic_connect_to_server(char *host_name, long port, long *fd) { char *dummy = NULL; int status; int result; HTSprintf0(&dummy, "%s//%s:%ld/", STR_WAIS_URL, host_name, port); status = HTDoConnect(dummy, "WAIS", 210, (int *) fd); if (status == HT_INTERRUPTED) { result = -1; } else if (status < 0) { result = 0; } else { result = 1; } FREE(dummy); return result; } /* Returns 1 on success, 0 on fail, -1 on interrupt. */ #ifdef VMS static int mosaic_connect_to_server(char *host_name, long port, long *fdp) #else static int mosaic_connect_to_server(char *host_name, long port, FILE **fp) #endif /* VMS */ { #ifndef VMS FILE *file; #endif /* VMS */ long fd; int rv; rv = fd_mosaic_connect_to_server(host_name, port, &fd); if (rv == 0) { HTAlert(gettext("Could not connect to WAIS server.")); return 0; } else if (rv == -1) { HTAlert(CONNECTION_INTERRUPTED); return -1; } #ifndef VMS if ((file = fdopen(fd, "r+")) == NULL) { HTAlert(gettext("Could not open WAIS connection for reading.")); return 0; } *fp = file; #else *fdp = fd; #endif /* VMS */ return 1; } /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* showDiags */ /* modified from Jonny G's version in ui/question.c */ static void showDiags(HTStream *target, diagnosticRecord ** d) { long i; for (i = 0; d[i] != NULL; i++) { if (d[i]->ADDINFO != NULL) { PUTS(gettext("Diagnostic code is ")); PUTS(d[i]->DIAG); PUTC(' '); PUTS(d[i]->ADDINFO); PUTC('\n'); } } } /* Matrix of allowed characters in filenames * ----------------------------------------- */ static BOOL acceptable[256]; static BOOL acceptable_inited = NO; static void init_acceptable(void) { unsigned int i; char *good = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$"; for (i = 0; i < 256; i++) acceptable[i] = NO; for (; *good; good++) acceptable[(unsigned int) *good] = YES; acceptable_inited = YES; } /* Transform file identifier into WWW address * ------------------------------------------ * * * On exit, * returns nil if error * pointer to malloced string (must be freed) if ok */ static char *WWW_from_archie(char *file) { char *end; char *result; char *colon; for (end = file; *end > ' '; end++) ; /* assumes ASCII encoding */ result = (char *) malloc(10 + (end - file)); if (!result) return result; /* Malloc error */ strcpy(result, "file://"); StrNCat(result, file, end - file); colon = StrChr(result + 7, ':'); /* Expect colon after host */ if (colon) { for (; colon[0]; colon[0] = colon[1], colon++) ; /* move down */ } return result; } /* WWW_from_archie */ /* Transform document identifier into URL * -------------------------------------- * * Bugs: A static buffer of finite size is used! * The format of the docid MUST be good! * * On exit, * returns nil if error * pointer to malloced string (must be freed) if ok */ static char hex[17] = "0123456789ABCDEF"; static char *WWW_from_WAIS(any *docid) { static char buf[BIG]; char *q = buf; char *p = (docid->bytes); char *result = NULL; int i, l; if (TRACE) { char *p2; fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size); for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) { if ((*p2 >= ' ') && (*p2 <= '~')) /* Assume ASCII! */ fprintf(tfp, "%c", *p2); else fprintf(tfp, "<%x>", (unsigned) *p2); } fprintf(tfp, "\n"); } for (p = docid->bytes; (p < docid->bytes + docid->size) && (q < &buf[BIG]);) { CTRACE((tfp, " Record type %d, length %d\n", p[0], p[1])); if (*p > 10) { CTRACE((tfp, "Eh? DOCID record type of %d!\n", *p)); return 0; } { /* Bug fix -- allow any byte value 15 Apr 93 */ unsigned int i2 = (unsigned) *p++; if (i2 > 99) { *q++ = (i2 / 100) + '0'; i2 = i2 % 100; } if (i2 > 9) { *q++ = (i2 / 10) + '0'; i2 = i2 % 10; } *q++ = i2 + '0'; /* Record type */ } *q++ = '='; /* Separate */ l = *p++; /* Length */ for (i = 0; i < l; i++, p++) { if (!acceptable[UCH(*p)]) { *q++ = HEX_ESCAPE; /* Means hex coming */ *q++ = hex[(*p) >> 4]; *q++ = hex[(*p) & 15]; } else *q++ = *p; } *q++ = ';'; /* Terminate field */ } *q++ = 0; /* Terminate string */ CTRACE((tfp, "WWW form of id: %s\n", buf)); StrAllocCopy(result, buf); return result; } /* WWW_from_WAIS */ /* Transform URL into WAIS document identifier * ------------------------------------------- * * On entry, * docname points to valid name produced originally by * WWW_from_WAIS * On exit, * docid->size is valid * docid->bytes is malloced and must later be freed. */ static any *WAIS_from_WWW(any *docid, char *docname) { char *z; /* Output pointer */ char *sor; /* Start of record - points to size field. */ char *p; /* Input pointer */ char *q; /* Poisition of "=" */ char *s; /* Position of semicolon */ int n; /* size */ CTRACE((tfp, "WWW id (to become WAIS id): %s\n", docname)); for (n = 0, p = docname; *p; p++) { /* Count sizes of strings */ n++; if (*p == ';') n--; /* Not converted */ else if (*p == HEX_ESCAPE) n = n - 2; /* Save two bytes */ docid->size = n; } if (!(docid->bytes = (char *) malloc(docid->size))) /* result record */ outofmem(__FILE__, "WAIS_from_WWW"); z = docid->bytes; for (p = docname; *p;) { /* Convert of strings */ /* Record type */ *z = 0; /* Initialize record type */ while (*p >= '0' && *p <= '9') { *z = *z * 10 + (*p++ - '0'); /* Decode decimal record type */ } z++; if (*p != '=') return 0; q = p; s = StrChr(q, ';'); /* (Check only) */ if (!s) return 0; /* Bad! No ';'; */ sor = z; /* Remember where the size field was */ z++; /* Skip record size for now */ for (p = q + 1; *p != ';';) { if (*p == HEX_ESCAPE) { char c; unsigned int b; p++; c = *p++; b = from_hex(c); c = *p++; if (!c) break; /* Odd number of chars! */ *z++ = (b << 4) + from_hex(c); } else { *z++ = *p++; /* Record */ } } *sor = (z - sor - 1); /* Fill in size -- not counting size itself */ p++; /* After semicolon: start of next record */ } if (TRACE) { char *p2; fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size); for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) { if ((*p2 >= ' ') && (*p2 <= '~')) /* Assume ASCII! */ fprintf(tfp, "%c", *p2); else fprintf(tfp, "<%x>", (unsigned) *p2); } fprintf(tfp, "\n"); } return docid; /* Ok */ } /* WAIS_from_WWW */ /* Send a plain text record to the client output_text_record() * -------------------------------------- */ static void output_text_record(HTStream *target, WAISDocumentText *record, boolean binary) { unsigned long count; /* printf(" Text\n"); print_any(" DocumentID: ", record->DocumentID); printf(" VersionNumber: %d\n", record->VersionNumber); */ if (binary) { (*target->isa->put_block) (target, record->DocumentText->bytes, record->DocumentText->size); return; } for (count = 0; count < record->DocumentText->size; count++) { long ch = (unsigned char) record->DocumentText->bytes[count]; if (ch == 27) { /* What is this in for? Tim */ /* then we have an escape code */ /* if the next letter is '(' or ')', then ignore two letters */ if ('(' == record->DocumentText->bytes[count + 1] || ')' == record->DocumentText->bytes[count + 1]) count += 1; /* it is a term marker */ else count += 4; /* it is a paragraph marker */ } else if (ch == '\n' || ch == '\r') { PUTC('\n'); } else if (IS_CJK_TTY || ch == '\t' || isprint(ch)) { PUTC(ch); } } } /* output text record */ /* Format A Search response for the client display_search_response * --------------------------------------- */ /* modified from tracy shen's version in wutil.c * displays either a text record or a set of headlines. */ static void display_search_response(HTStructured * target, SearchResponseAPDU *response, char *the_database, char *keywords) { WAISSearchResponse *info; long i, k; BOOL archie = strstr(the_database, "archie") != 0; /* Special handling */ CTRACE((tfp, "HTWAIS: Displaying search response\n")); PUTS(gettext("Index ")); START(HTML_EM); PUTS(the_database); END(HTML_EM); sprintf(line, gettext(" contains the following %d item%s relevant to \""), (int) (response->NumberOfRecordsReturned), response->NumberOfRecordsReturned == 1 ? "" : "s"); PUTS(line); START(HTML_EM); PUTS(keywords); END(HTML_EM); PUTS("\".\n"); PUTS(gettext("The first figure after each entry is its relative score, ")); PUTS(gettext("the second is the number of lines in the item.")); START(HTML_BR); START(HTML_BR); PUTC('\n'); START(HTML_OL); if (response->DatabaseDiagnosticRecords != 0) { info = (WAISSearchResponse *) response->DatabaseDiagnosticRecords; i = 0; if (info->Diagnostics != NULL) showDiags((HTStream *) target, info->Diagnostics); if (info->DocHeaders != 0) { for (k = 0; info->DocHeaders[k] != 0; k++) { WAISDocumentHeader *head = info->DocHeaders[k]; char *headline = trim_junk(head->Headline); any *docid = head->DocumentID; char *docname; /* printable version of docid */ i++; /* * Make a printable string out of the document id. */ CTRACE((tfp, "HTWAIS: %2ld: Score: %4ld, lines:%4ld '%s'\n", i, (long int) (info->DocHeaders[k]->Score), (long int) (info->DocHeaders[k]->Lines), headline)); START(HTML_LI); if (archie) { char *www_name = WWW_from_archie(headline); if (www_name) { HTStartAnchor(target, NULL, www_name); PUTS(headline); END(HTML_A); FREE(www_name); } else { PUTS(headline); PUTS(gettext(" (bad file name)")); } } else { /* Not archie */ docname = WWW_from_WAIS(docid); if (docname) { if ((head->Types) && (!strcmp(head->Types[0], "URL"))) { HTStartAnchor(target, NULL, headline); } else { char *dbname = HTEscape(the_database, URL_XPALPHAS); char *w3_address = NULL; HTSprintf0(&w3_address, "/%s/%s/%d/%s", dbname, head->Types ? head->Types[0] : "TEXT", (int) (head->DocumentLength), docname); HTStartAnchor(target, NULL, w3_address); FREE(w3_address); FREE(dbname); } PUTS(headline); END(HTML_A); FREE(docname); } else { PUTS(gettext("(bad doc id)")); } } sprintf(line, "%5ld %5ld ", head->Score, head->Lines); PUTS(line); MAYBE_END(HTML_LI); } /* next document header */ } /* if there were any document headers */ if (info->ShortHeaders != 0) { k = 0; while (info->ShortHeaders[k] != 0) { i++; PUTS(gettext("(Short Header record, can't display)")); } } if (info->LongHeaders != 0) { k = 0; while (info->LongHeaders[k] != 0) { i++; PUTS(gettext("\nLong Header record, can't display\n")); } } if (info->Text != 0) { k = 0; while (info->Text[k] != 0) { i++; PUTS(gettext("\nText record\n")); output_text_record((HTStream *) target, info->Text[k++], false); } } if (info->Headlines != 0) { k = 0; while (info->Headlines[k] != 0) { i++; PUTS(gettext("\nHeadline record, can't display\n")); /* dsply_headline_record( info->Headlines[k++]); */ } } if (info->Codes != 0) { k = 0; while (info->Codes[k] != 0) { i++; PUTS(gettext("\nCode record, can't display\n")); /* dsply_code_record( info->Codes[k++]); */ } } } /* Loop: display user info */ END(HTML_OL); PUTC('\n'); } /* Load by name HTLoadWAIS * ============ * * This renders any object or search as required. */ int HTLoadWAIS(const char *arg, HTParentAnchor *anAnchor, HTFormat format_out, HTStream *sink) #define MAX_KEYWORDS_LENGTH 1000 #define MAX_SERVER_LENGTH 1000 #define MAX_DATABASE_LENGTH 1000 #define MAX_SERVICE_LENGTH 1000 #define MAXDOCS 200 { char *key; /* pointer to keywords in URL */ char *request_message = NULL; /* arbitrary message limit */ char *response_message = NULL; /* arbitrary message limit */ long request_buffer_length; /* how of the request is left */ SearchResponseAPDU *retrieval_response = 0; char keywords[MAX_KEYWORDS_LENGTH + 1]; char *the_server_name; char *wais_database = NULL; /* name of current database */ char *www_database; /* Same name escaped */ char *service; char *doctype; char *doclength; long document_length = 0; char *docname = 0; #ifdef VMS long connection = 0; #else FILE *connection = NULL; #endif /* VMS */ char *names; /* Copy of arg to be hacked up */ BOOL ok = NO; int return_status = HT_LOADED; int rv; if (!acceptable_inited) init_acceptable(); /* Decipher and check syntax of WWW address: * ---------------------------------------- * * First we remove the "wais:" if it was specified. 920110 */ names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION); key = StrChr(names, '?'); if (key) { char *p; *key++ = 0; /* Split off keywords */ for (p = key; *p; p++) if (*p == '+') *p = ' '; HTUnEscape(key); } if (names[0] == '/') { the_server_name = names + 1; if ((as_gate = (*the_server_name == '/')) != 0) the_server_name++; /* Accept one or two */ www_database = StrChr(the_server_name, '/'); if (www_database) { *www_database++ = 0; /* Separate database name */ doctype = StrChr(www_database, '/'); if (key) ok = YES; /* Don't need doc details */ else if (doctype) { /* If not search parse doc details */ *doctype++ = 0; /* Separate rest of doc address */ doclength = StrChr(doctype, '/'); if (doclength) { *doclength++ = 0; document_length = atol(doclength); if (document_length) { docname = StrChr(doclength, '/'); if (docname) { *docname++ = 0; ok = YES; /* To avoid a goto! */ } /* if docname */ } /* if document_length valid */ } /* if doclength */ } else { /* no doctype? Assume index required */ if (!key) key = ""; ok = YES; } /* if doctype */ } /* if database */ } if (!ok) return HTLoadError(sink, 500, gettext("Syntax error in WAIS URL")); CTRACE((tfp, "HTWAIS: Parsed OK\n")); service = StrChr(names, ':'); if (service) *service++ = 0; else service = "210"; if (the_server_name[0] == 0) { #ifdef VMS connection = 0; #else connection = NULL; #endif /* VMS */ } else if (!(key && !*key)) { int status; CTRACE((tfp, "===WAIS=== calling mosaic_connect_to_server\n")); status = mosaic_connect_to_server(the_server_name, atoi(service), &connection); if (status == 0) { CTRACE((tfp, "===WAIS=== connection failed\n")); FREE(names); return HT_NOT_LOADED; } else if (status == -1) { CTRACE((tfp, "===WAIS=== connection interrupted\n")); FREE(names); return HT_NOT_LOADED; } } StrAllocCopy(wais_database, www_database); HTUnEscape(wais_database); /* * This below fixed size stuff is terrible. */ #ifdef VMS if ((request_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0) outofmem(__FILE__, "HTLoadWAIS"); if ((response_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0) outofmem(__FILE__, "HTLoadWAIS"); #else request_message = (char *) s_malloc((size_t) MAX_MESSAGE_LEN * sizeof(char)); response_message = (char *) s_malloc((size_t) MAX_MESSAGE_LEN * sizeof(char)); #endif /* VMS */ /* * If keyword search is performed but there are no keywords, the user has * followed a link to the index itself. It would be appropriate at this * point to send him the .SRC file - how? */ if (key && !*key) { /* I N D E X */ #ifdef CACHE_FILE_PREFIX char *filename = NULL; FILE *fp; #endif HTStructured *target = HTML_new(anAnchor, format_out, sink); START(HTML_HEAD); PUTC('\n'); HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL); PUTC('\n'); { START(HTML_TITLE); PUTS(wais_database); PUTS(gettext(" (WAIS Index)")); END(HTML_TITLE); PUTC('\n'); END(HTML_HEAD); PUTC('\n'); START(HTML_H1); PUTS(gettext("WAIS Index: ")); START(HTML_EM); PUTS(wais_database); END(HTML_EM); END(HTML_H1); PUTC('\n'); PUTS(gettext("This is a link for searching the ")); START(HTML_EM); PUTS(wais_database); END(HTML_EM); PUTS(gettext(" WAIS Index.\n")); } /* * If we have seen a source file for this database, use that. */ #ifdef CACHE_FILE_PREFIX HTSprintf0(&filename, "%sWSRC-%s:%s:%.100s.txt", CACHE_FILE_PREFIX, the_server_name, service, www_database); fp = fopen(filename, "r"); /* Have we found this already? */ CTRACE((tfp, "HTWAIS: Description of server %s %s.\n", filename, fp ? "exists already" : "does NOT exist!")); if (fp) { char c; START(HTML_PRE); /* Preformatted description */ PUTC('\n'); while ((c = getc(fp)) != EOF) PUTC(c); /* Transfer file */ END(HTML_PRE); fclose(fp); } FREE(filename); #endif START(HTML_P); PUTS(gettext("\nEnter the 's'earch command and then specify search words.\n")); FREE_TARGET; } else if (key) { /* S E A R C H */ char *p; HTStructured *target; LYStrNCpy(keywords, key, MAX_KEYWORDS_LENGTH); while ((p = StrChr(keywords, '+')) != 0) *p = ' '; /* * Send advance title to get something fast to the other end. */ target = HTML_new(anAnchor, format_out, sink); START(HTML_HEAD); PUTC('\n'); HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL); PUTC('\n'); START(HTML_TITLE); PUTS(keywords); PUTS(gettext(" (in ")); PUTS(wais_database); PUTC(')'); END(HTML_TITLE); PUTC('\n'); END(HTML_HEAD); PUTC('\n'); START(HTML_H1); PUTS(gettext("WAIS Search of \"")); START(HTML_EM); PUTS(keywords); END(HTML_EM); PUTS(gettext("\" in: ")); START(HTML_EM); PUTS(wais_database); END(HTML_EM); END(HTML_H1); PUTC('\n'); request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */ CTRACE((tfp, "HTWAIS: Search for `%s' in `%s'\n", keywords, wais_database)); if (NULL == generate_search_apdu(request_message + HEADER_LENGTH, &request_buffer_length, keywords, wais_database, NULL, MAXDOCS)) { #ifdef VMS HTAlert(gettext("HTWAIS: Request too large.")); return_status = HT_NOT_LOADED; FREE_TARGET; goto CleanUp; #else panic("request too large"); #endif /* VMS */ } HTProgress(gettext("Searching WAIS database...")); rv = interpret_message(request_message, MAX_MESSAGE_LEN - request_buffer_length, response_message, MAX_MESSAGE_LEN, connection, false /* true verbose */ ); if (rv == HT_INTERRUPTED) { HTAlert(gettext("Search interrupted.")); return_status = HT_INTERRUPTED; FREE_TARGET; goto CleanUp; } else if (!rv) { #ifdef VMS HTAlert(HTWAIS_MESSAGE_TOO_BIG); return_status = HT_NOT_LOADED; FREE_TARGET; goto CleanUp; #else panic("returned message too large"); #endif /* VMS */ } else { /* returned message ok */ SearchResponseAPDU *query_response = 0; readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH); display_search_response(target, query_response, wais_database, keywords); if (query_response->DatabaseDiagnosticRecords) freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords); freeSearchResponseAPDU(query_response); } /* returned message not too large */ FREE_TARGET; } else { /* D O C U M E N T F E T C H */ HTFormat format_in; boolean binary; /* how to transfer stuff coming over */ HTStream *target; long count; any doc_chunk; any *docid = &doc_chunk; CTRACE((tfp, "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n", NonNull(docname), doctype, document_length)); format_in = !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") : !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") : !strcmp(doctype, "HTML") ? HTAtom_for("text/html") : !strcmp(doctype, "GIF") ? HTAtom_for("image/gif") : HTAtom_for("application/octet-stream"); binary = 0 != strcmp(doctype, "WSRC") && 0 != strcmp(doctype, "TEXT") && 0 != strcmp(doctype, "HTML"); target = HTStreamStack(format_in, format_out, sink, anAnchor); if (!target) return HTLoadError(sink, 500, gettext("Can't convert format of WAIS document")); /* * Decode hex or litteral format for document ID. */ WAIS_from_WWW(docid, docname); /* * Loop over slices of the document. */ for (count = 0; count * CHARS_PER_PAGE < document_length; count++) { #ifdef VMS char *type = NULL; StrAllocCopy(type, doctype); #else char *type = s_strdup(doctype); /* Gets freed I guess */ #endif /* VMS */ request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */ CTRACE((tfp, "HTWAIS: Slice number %ld\n", count)); if (HTCheckForInterrupt()) { HTAlert(TRANSFER_INTERRUPTED); (*target->isa->_abort) (target, NULL); #ifdef VMS FREE(type); #endif /* VMS */ return_status = HT_NOT_LOADED; goto CleanUp; } if (0 == generate_retrieval_apdu(request_message + HEADER_LENGTH, &request_buffer_length, docid, CT_byte, count * CHARS_PER_PAGE, (((count + 1) * CHARS_PER_PAGE <= document_length) ? (count + 1) * CHARS_PER_PAGE : document_length), type, wais_database)) { #ifdef VMS HTAlert(gettext("HTWAIS: Request too long.")); return_status = HT_NOT_LOADED; FREE_TARGET; FREE(type); FREE(docid->bytes); goto CleanUp; #else panic("request too long"); #endif /* VMS */ } /* * Actually do the transaction given by request_message. */ HTProgress(gettext("Fetching WAIS document...")); rv = interpret_message(request_message, MAX_MESSAGE_LEN - request_buffer_length, response_message, MAX_MESSAGE_LEN, connection, false /* true verbose */ ); if (rv == HT_INTERRUPTED) { HTAlert(TRANSFER_INTERRUPTED); return_status = HT_INTERRUPTED; FREE_TARGET; FREE(type); FREE(docid->bytes); goto CleanUp; } else if (!rv) { #ifdef VMS HTAlert(HTWAIS_MESSAGE_TOO_BIG); return_status = HT_NOT_LOADED; FREE_TARGET; FREE(type); FREE(docid->bytes); goto CleanUp; #else panic("Returned message too large"); #endif /* VMS */ } /* * Parse the result which came back into memory. */ readSearchResponseAPDU(&retrieval_response, response_message + HEADER_LENGTH); if (NULL == ((WAISSearchResponse *) retrieval_response->DatabaseDiagnosticRecords)->Text) { /* display_search_response(target, retrieval_response, wais_database, keywords); */ PUTS(gettext("No text was returned!\n")); /* panic("No text was returned"); */ } else { output_text_record(target, ((WAISSearchResponse *) retrieval_response->DatabaseDiagnosticRecords)->Text[0], binary); } /* If text existed */ #ifdef VMS FREE(type); #endif /* VMS */ } /* Loop over slices */ FREE_TARGET; FREE(docid->bytes); freeWAISSearchResponse(retrieval_response->DatabaseDiagnosticRecords); freeSearchResponseAPDU(retrieval_response); } /* If document rather than search */ CleanUp: /* * (This postponed until later, after a timeout:) */ #ifdef VMS if (connection) NETCLOSE((int) connection); #else if (connection) fclose(connection); #endif /* VMS */ FREE(wais_database); #ifdef VMS FREE(request_message); FREE(response_message); #else s_free(request_message); s_free(response_message); #endif /* VMS */ FREE(names); return (return_status); } #ifdef GLOBALDEF_IS_MACRO #define _HTWAIS_C_1_INIT { "wais", HTLoadWAIS, NULL } GLOBALDEF(HTProtocol, HTWAIS, _HTWAIS_C_1_INIT); #else GLOBALDEF HTProtocol HTWAIS = {"wais", HTLoadWAIS, NULL}; #endif /* GLOBALDEF_IS_MACRO */