fserve.c revision c7b4381a
1a96d7823Smrg/*
2a96d7823Smrg
3a96d7823SmrgCopyright 1990, 1998  The Open Group
4a96d7823Smrg
5a96d7823SmrgPermission to use, copy, modify, distribute, and sell this software and its
6a96d7823Smrgdocumentation for any purpose is hereby granted without fee, provided that
7a96d7823Smrgthe above copyright notice appear in all copies and that both that
8a96d7823Smrgcopyright notice and this permission notice appear in supporting
9a96d7823Smrgdocumentation.
10a96d7823Smrg
11a96d7823SmrgThe above copyright notice and this permission notice shall be included in
12a96d7823Smrgall copies or substantial portions of the Software.
13a96d7823Smrg
14a96d7823SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a96d7823SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a96d7823SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17a96d7823SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18a96d7823SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19a96d7823SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20a96d7823Smrg
21a96d7823SmrgExcept as contained in this notice, the name of The Open Group shall not be
22a96d7823Smrgused in advertising or otherwise to promote the sale, use or other dealings
23a96d7823Smrgin this Software without prior written authorization from The Open Group.
24a96d7823Smrg
25a96d7823Smrg*/
26a96d7823Smrg
27a96d7823Smrg/*
28a96d7823Smrg * Copyright 1990 Network Computing Devices
29a96d7823Smrg *
30a96d7823Smrg * Permission to use, copy, modify, distribute, and sell this software and
31a96d7823Smrg * its documentation for any purpose is hereby granted without fee, provided
32a96d7823Smrg * that the above copyright notice appear in all copies and that both that
33a96d7823Smrg * copyright notice and this permission notice appear in supporting
34a96d7823Smrg * documentation, and that the names of Network Computing Devices, or Digital
35a96d7823Smrg * not be used in advertising or publicity pertaining to distribution
36a96d7823Smrg * of the software without specific, written prior permission.
37a96d7823Smrg *
38a96d7823Smrg * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
39a96d7823Smrg * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
40a96d7823Smrg * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
41a96d7823Smrg * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
42a96d7823Smrg * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
43a96d7823Smrg * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
44a96d7823Smrg * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
45a96d7823Smrg * THIS SOFTWARE.
46a96d7823Smrg *
47a96d7823Smrg * Author:  	Dave Lemke, Network Computing Devices, Inc
48a96d7823Smrg */
49a96d7823Smrg/*
50a96d7823Smrg * font server specific font access
51a96d7823Smrg */
52a96d7823Smrg
53a96d7823Smrg#ifdef HAVE_CONFIG_H
54a96d7823Smrg#include <config.h>
55a96d7823Smrg#endif
56a96d7823Smrg#include "libxfontint.h"
57c7b4381aSmrg#include "src/util/replace.h"
58a96d7823Smrg
59a96d7823Smrg#ifdef WIN32
60a96d7823Smrg#define _WILLWINSOCK_
61a96d7823Smrg#endif
62a96d7823Smrg#define FONT_t
63a96d7823Smrg#define TRANS_CLIENT
64a96d7823Smrg#include	"X11/Xtrans/Xtrans.h"
65a96d7823Smrg#include	"X11/Xpoll.h"
66a96d7823Smrg#include	<X11/fonts/FS.h>
67a96d7823Smrg#include	<X11/fonts/FSproto.h>
68a96d7823Smrg#include	<X11/X.h>
69a96d7823Smrg#include	<X11/Xos.h>
70a96d7823Smrg#include	<X11/fonts/fontmisc.h>
71a96d7823Smrg#include	<X11/fonts/fontstruct.h>
72a96d7823Smrg#include	"fservestr.h"
73a96d7823Smrg#include	<X11/fonts/fontutil.h>
74a96d7823Smrg#include	<errno.h>
75a96d7823Smrg#include	<limits.h>
76a96d7823Smrg
77a96d7823Smrg#include	<time.h>
78a96d7823Smrg#define Time_t time_t
79a96d7823Smrg
80a96d7823Smrg#ifdef NCD
81a96d7823Smrg#include	<ncd/nvram.h>
82a96d7823Smrg#endif
83a96d7823Smrg
84a96d7823Smrg#include <stddef.h>
85a96d7823Smrg
86a96d7823Smrg#ifndef MIN
87a96d7823Smrg#define MIN(a,b)    ((a)<(b)?(a):(b))
88a96d7823Smrg#endif
89a96d7823Smrg#define TimeCmp(a,c,b)	((int) ((a) - (b)) c 0)
90a96d7823Smrg
91a96d7823Smrg#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
92a96d7823Smrg			     (pci)->rightSideBearing || \
93a96d7823Smrg			     (pci)->ascent || \
94a96d7823Smrg			     (pci)->descent || \
95a96d7823Smrg			     (pci)->characterWidth)
96a96d7823Smrg
97a96d7823Smrg/*
98a96d7823Smrg * SIZEOF(r) is in bytes, length fields in the protocol are in 32-bit words,
99a96d7823Smrg * so this converts for doing size comparisons.
100a96d7823Smrg */
101a96d7823Smrg#define LENGTHOF(r)	(SIZEOF(r) >> 2)
102a96d7823Smrg
103a96d7823Smrg/* Somewhat arbitrary limit on maximum reply size we'll try to read. */
104a96d7823Smrg#define MAX_REPLY_LENGTH	((64 * 1024 * 1024) >> 2)
105a96d7823Smrg
106a96d7823Smrgstatic int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
107a96d7823Smrgstatic int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
108a96d7823Smrgstatic int fs_read_list_info ( FontPathElementPtr fpe,
109a96d7823Smrg			       FSBlockDataPtr blockrec );
110a96d7823Smrg
111a96d7823Smrgstatic void fs_block_handler ( void *wt );
112a96d7823Smrg
113a96d7823Smrgstatic int fs_wakeup ( FontPathElementPtr fpe );
114a96d7823Smrg
115a96d7823Smrg/*
116a96d7823Smrg * List of all FPEs
117a96d7823Smrg */
118a96d7823Smrgstatic FSFpePtr fs_fpes;
119a96d7823Smrg/*
120a96d7823Smrg * Union of all FPE blockStates
121a96d7823Smrg */
122a96d7823Smrgstatic CARD32	fs_blockState;
123a96d7823Smrg
124a96d7823Smrgstatic int _fs_restart_connection ( FSFpePtr conn );
125a96d7823Smrgstatic void fs_send_query_bitmaps ( FontPathElementPtr fpe,
126a96d7823Smrg				   FSBlockDataPtr blockrec );
127a96d7823Smrgstatic int fs_send_close_font ( FontPathElementPtr fpe, Font id );
128a96d7823Smrgstatic void fs_client_died ( pointer client, FontPathElementPtr fpe );
129a96d7823Smrgstatic void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
130a96d7823Smrgstatic void _fs_client_resolution ( FSFpePtr conn );
131a96d7823Smrgstatic fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
132a96d7823Smrgstatic int fs_await_reply (FSFpePtr conn);
133a96d7823Smrgstatic void _fs_do_blocked (FSFpePtr conn);
134a96d7823Smrgstatic void fs_cleanup_bfont (FSBlockedFontPtr bfont);
135a96d7823Smrg
136a96d7823Smrgchar _fs_glyph_undefined;
137a96d7823Smrgchar _fs_glyph_requested;
138a96d7823Smrgstatic char _fs_glyph_zero_length;
139a96d7823Smrg
140a96d7823Smrgstatic int  generationCount;
141a96d7823Smrg
142a96d7823Smrgstatic int FontServerRequestTimeout = 30 * 1000;
143a96d7823Smrg
144a96d7823Smrgstatic void
145a96d7823Smrg_fs_close_server (FSFpePtr conn);
146a96d7823Smrg
147a96d7823Smrgstatic FSFpePtr
148a96d7823Smrg_fs_init_conn (const char *servername, FontPathElementPtr fpe);
149a96d7823Smrg
150a96d7823Smrgstatic int
151a96d7823Smrg_fs_wait_connect (FSFpePtr conn);
152a96d7823Smrg
153a96d7823Smrgstatic int
154a96d7823Smrg_fs_send_init_packets (FSFpePtr conn);
155a96d7823Smrg
156a96d7823Smrgstatic void
157a96d7823Smrg_fs_check_reconnect (FSFpePtr conn);
158a96d7823Smrg
159a96d7823Smrgstatic void
160a96d7823Smrg_fs_start_reconnect (FSFpePtr conn);
161a96d7823Smrg
162a96d7823Smrgstatic void
163a96d7823Smrg_fs_free_conn (FSFpePtr conn);
164a96d7823Smrg
165a96d7823Smrgstatic int
166a96d7823Smrgfs_free_fpe(FontPathElementPtr fpe);
167a96d7823Smrg
168a96d7823Smrgstatic void
169a96d7823Smrgfs_fd_handler(int fd, void *data);
170a96d7823Smrg
171a96d7823Smrg/*
172a96d7823Smrg * Font server access
173a96d7823Smrg *
174a96d7823Smrg * the basic idea for the non-blocking access is to have the function
175a96d7823Smrg * called multiple times until the actual data is returned, instead
176a96d7823Smrg * of ClientBlocked.
177a96d7823Smrg *
178a96d7823Smrg * the first call to the function will cause the request to be sent to
179a96d7823Smrg * the font server, and a block record to be stored in the fpe's list
180a96d7823Smrg * of outstanding requests.  the FS block handler also sticks the
181a96d7823Smrg * proper set of fd's into the select mask.  when data is ready to be
182a96d7823Smrg * read in, the FS wakup handler will be hit.  this will read the
183a96d7823Smrg * data off the wire into the proper block record, and then signal the
184a96d7823Smrg * client that caused the block so that it can restart.  it will then
185a96d7823Smrg * call the access function again, which will realize that the data has
186a96d7823Smrg * arrived and return it.
187a96d7823Smrg */
188a96d7823Smrg
189a96d7823Smrg
190a96d7823Smrg#ifdef DEBUG
191a96d7823Smrgstatic void
192a96d7823Smrg_fs_add_req_log(FSFpePtr conn, int opcode)
193a96d7823Smrg{
194a96d7823Smrg    conn->current_seq++;
195a96d7823Smrg    fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
196a96d7823Smrg	     conn->current_seq, opcode);
197a96d7823Smrg    conn->reqbuffer[conn->reqindex].opcode = opcode;
198a96d7823Smrg    conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
199a96d7823Smrg    conn->reqindex++;
200a96d7823Smrg    if (conn->reqindex == REQUEST_LOG_SIZE)
201a96d7823Smrg	conn->reqindex = 0;
202a96d7823Smrg}
203a96d7823Smrg
204a96d7823Smrgstatic void
205a96d7823Smrg_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
206a96d7823Smrg{
207a96d7823Smrg    int	    i;
208a96d7823Smrg
209a96d7823Smrg    for (i = 0; i < REQUEST_LOG_SIZE; i++)
210a96d7823Smrg	if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
211a96d7823Smrg	    break;
212a96d7823Smrg    if (i == REQUEST_LOG_SIZE)
213a96d7823Smrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: unknown\n",
214a96d7823Smrg		 rep->sequenceNumber);
215a96d7823Smrg    else
216a96d7823Smrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: %d\n",
217a96d7823Smrg		 rep->sequenceNumber,
218a96d7823Smrg		 conn->reqbuffer[i].opcode);
219a96d7823Smrg}
220a96d7823Smrg
221a96d7823Smrg#define _fs_reply_failed(rep, name, op) do {                            \
222a96d7823Smrg    if (rep) {                                                          \
223a96d7823Smrg        if (rep->type == FS_Error)                                      \
224a96d7823Smrg            fprintf (stderr, "Error: %d Request: %s\n",                 \
225a96d7823Smrg                     ((fsError *)rep)->request, #name);                 \
226a96d7823Smrg        else                                                            \
227c7b4381aSmrg            fprintf (stderr, "Bad Length for %s Reply: %u %s %d\n",     \
228c7b4381aSmrg                     #name, (unsigned) rep->length, op, LENGTHOF(name));\
229a96d7823Smrg    }                                                                   \
230a96d7823Smrg} while (0)
231a96d7823Smrg
232a96d7823Smrg#else
233a96d7823Smrg#define _fs_add_req_log(conn,op)    ((conn)->current_seq++)
234a96d7823Smrg#define _fs_add_rep_log(conn,rep)
235a96d7823Smrg#define _fs_reply_failed(rep,name,op)
236a96d7823Smrg#endif
237a96d7823Smrg
238a96d7823Smrgstatic Bool
239a96d7823Smrgfs_name_check(const char *name)
240a96d7823Smrg{
241a96d7823Smrg    /* Just make sure there is a protocol/ prefix */
242a96d7823Smrg    return (name && *name != '/' && strchr(name, '/'));
243a96d7823Smrg}
244a96d7823Smrg
245a96d7823Smrgstatic void
246a96d7823Smrg_fs_client_resolution(FSFpePtr conn)
247a96d7823Smrg{
248a96d7823Smrg    fsSetResolutionReq srreq;
249a96d7823Smrg    int         num_res;
250a96d7823Smrg    FontResolutionPtr res;
251a96d7823Smrg
252a96d7823Smrg    res = GetClientResolutions(&num_res);
253a96d7823Smrg
254a96d7823Smrg    if (num_res) {
255a96d7823Smrg	srreq.reqType = FS_SetResolution;
256a96d7823Smrg	srreq.num_resolutions = num_res;
257a96d7823Smrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
258a96d7823Smrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
259a96d7823Smrg
260a96d7823Smrg	_fs_add_req_log(conn, FS_SetResolution);
261a96d7823Smrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
262a96d7823Smrg	    (void)_fs_write_pad(conn, (char *) res,
263a96d7823Smrg				(num_res * SIZEOF(fsResolution)));
264a96d7823Smrg    }
265a96d7823Smrg}
266a96d7823Smrg
267a96d7823Smrg/*
268a96d7823Smrg * close font server and remove any state associated with
269a96d7823Smrg * this connection - this includes any client records.
270a96d7823Smrg */
271a96d7823Smrg
272a96d7823Smrgstatic void
273a96d7823Smrgfs_close_conn(FSFpePtr conn)
274a96d7823Smrg{
275a96d7823Smrg    FSClientPtr	client, nclient;
276a96d7823Smrg
277a96d7823Smrg    _fs_close_server (conn);
278a96d7823Smrg
279a96d7823Smrg    for (client = conn->clients; client; client = nclient)
280a96d7823Smrg    {
281a96d7823Smrg	nclient = client->next;
282a96d7823Smrg	free (client);
283a96d7823Smrg    }
284a96d7823Smrg    conn->clients = NULL;
285a96d7823Smrg}
286a96d7823Smrg
287a96d7823Smrg/*
288a96d7823Smrg * the wakeup handlers have to be set when the FPE is open, and not
289a96d7823Smrg * removed until it is freed, in order to handle unexpected data, like
290a96d7823Smrg * events
291a96d7823Smrg */
292a96d7823Smrg/* ARGSUSED */
293a96d7823Smrgstatic int
294a96d7823Smrgfs_init_fpe(FontPathElementPtr fpe)
295a96d7823Smrg{
296a96d7823Smrg    FSFpePtr    conn;
297a96d7823Smrg    const char  *name;
298a96d7823Smrg    int         err;
299a96d7823Smrg    int		ret;
300a96d7823Smrg
301a96d7823Smrg    /* open font server */
302a96d7823Smrg    /* create FS specific fpe info */
303a96d7823Smrg    name = fpe->name;
304a96d7823Smrg
305a96d7823Smrg    /* hack for old style names */
306a96d7823Smrg    if (*name == ':')
307a96d7823Smrg	name++;			/* skip ':' */
308a96d7823Smrg
309a96d7823Smrg    conn = _fs_init_conn (name, fpe);
310a96d7823Smrg    if (!conn)
311a96d7823Smrg	err = AllocError;
312a96d7823Smrg    else
313a96d7823Smrg    {
314a96d7823Smrg	err = init_fs_handlers2 (fpe, fs_block_handler);
315a96d7823Smrg	if (err != Successful)
316a96d7823Smrg	{
317a96d7823Smrg	    _fs_free_conn (conn);
318a96d7823Smrg	    err = AllocError;
319a96d7823Smrg	}
320a96d7823Smrg	else
321a96d7823Smrg	{
322a96d7823Smrg	    fpe->private = conn;
323a96d7823Smrg	    conn->next = fs_fpes;
324a96d7823Smrg	    fs_fpes = conn;
325a96d7823Smrg	    ret = _fs_wait_connect (conn);
326a96d7823Smrg	    if (ret != FSIO_READY)
327a96d7823Smrg	    {
328a96d7823Smrg		fs_free_fpe (fpe);
329a96d7823Smrg		err = BadFontPath;
330a96d7823Smrg	    }
331a96d7823Smrg	    else
332a96d7823Smrg		err = Successful;
333a96d7823Smrg	}
334a96d7823Smrg    }
335a96d7823Smrg
336a96d7823Smrg    if (err == Successful)
337a96d7823Smrg    {
338a96d7823Smrg#ifdef NCD
339a96d7823Smrg	if (configData.ExtendedFontDiags)
340a96d7823Smrg	    printf("Connected to font server \"%s\"\n", name);
341a96d7823Smrg#endif
342a96d7823Smrg#ifdef DEBUG
343a96d7823Smrg	fprintf (stderr, "connected to FS \"%s\"\n", name);
344a96d7823Smrg#endif
345a96d7823Smrg    }
346a96d7823Smrg    else
347a96d7823Smrg    {
348a96d7823Smrg#ifdef DEBUG
349a96d7823Smrg	fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
350a96d7823Smrg#endif
351a96d7823Smrg#ifdef NCD
352a96d7823Smrg	if (configData.ExtendedFontDiags)
353a96d7823Smrg	    printf("Failed to connect to font server \"%s\"\n", name);
354a96d7823Smrg#endif
355a96d7823Smrg	;
356a96d7823Smrg    }
357a96d7823Smrg    return err;
358a96d7823Smrg}
359a96d7823Smrg
360a96d7823Smrgstatic int
361a96d7823Smrgfs_reset_fpe(FontPathElementPtr fpe)
362a96d7823Smrg{
363a96d7823Smrg    (void) _fs_send_init_packets((FSFpePtr) fpe->private);
364a96d7823Smrg    return Successful;
365a96d7823Smrg}
366a96d7823Smrg
367a96d7823Smrg/*
368a96d7823Smrg * this shouldn't be called till all refs to the FPE are gone
369a96d7823Smrg */
370a96d7823Smrg
371a96d7823Smrgstatic int
372a96d7823Smrgfs_free_fpe(FontPathElementPtr fpe)
373a96d7823Smrg{
374a96d7823Smrg    FSFpePtr    conn = (FSFpePtr) fpe->private, *prev;
375a96d7823Smrg
376a96d7823Smrg    /* unhook from chain of all font servers */
377a96d7823Smrg    for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
378a96d7823Smrg    {
379a96d7823Smrg	if (*prev == conn)
380a96d7823Smrg	{
381a96d7823Smrg	    *prev = conn->next;
382a96d7823Smrg	    break;
383a96d7823Smrg	}
384a96d7823Smrg    }
385a96d7823Smrg    _fs_unmark_block (conn, conn->blockState);
386a96d7823Smrg    fs_close_conn(conn);
387a96d7823Smrg    remove_fs_handlers2(fpe, fs_block_handler, fs_fpes == 0);
388a96d7823Smrg    _fs_free_conn (conn);
389a96d7823Smrg    fpe->private = (pointer) 0;
390a96d7823Smrg
391a96d7823Smrg#ifdef NCD
392a96d7823Smrg    if (configData.ExtendedFontDiags)
393a96d7823Smrg	printf("Disconnected from font server \"%s\"\n", fpe->name);
394a96d7823Smrg#endif
395a96d7823Smrg#ifdef DEBUG
396a96d7823Smrg    fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
397a96d7823Smrg#endif
398a96d7823Smrg
399a96d7823Smrg    return Successful;
400a96d7823Smrg}
401a96d7823Smrg
402a96d7823Smrgstatic      FSBlockDataPtr
403a96d7823Smrgfs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
404a96d7823Smrg{
405a96d7823Smrg    FSBlockDataPtr blockrec,
406a96d7823Smrg                *prev;
407a96d7823Smrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
408a96d7823Smrg    int         size;
409a96d7823Smrg
410a96d7823Smrg    switch (type) {
411a96d7823Smrg    case FS_OPEN_FONT:
412a96d7823Smrg	size = sizeof(FSBlockedFontRec);
413a96d7823Smrg	break;
414a96d7823Smrg    case FS_LOAD_GLYPHS:
415a96d7823Smrg	size = sizeof(FSBlockedGlyphRec);
416a96d7823Smrg	break;
417a96d7823Smrg    case FS_LIST_FONTS:
418a96d7823Smrg	size = sizeof(FSBlockedListRec);
419a96d7823Smrg	break;
420a96d7823Smrg    case FS_LIST_WITH_INFO:
421a96d7823Smrg	size = sizeof(FSBlockedListInfoRec);
422a96d7823Smrg	break;
423a96d7823Smrg    default:
424a96d7823Smrg	size = 0;
425a96d7823Smrg	break;
426a96d7823Smrg    }
427a96d7823Smrg    blockrec = malloc(sizeof(FSBlockDataRec) + size);
428a96d7823Smrg    if (!blockrec)
429a96d7823Smrg	return (FSBlockDataPtr) 0;
430a96d7823Smrg    blockrec->data = (pointer) (blockrec + 1);
431a96d7823Smrg    blockrec->client = client;
432a96d7823Smrg    blockrec->sequenceNumber = -1;
433a96d7823Smrg    blockrec->errcode = StillWorking;
434a96d7823Smrg    blockrec->type = type;
435a96d7823Smrg    blockrec->depending = 0;
436a96d7823Smrg    blockrec->next = (FSBlockDataPtr) 0;
437a96d7823Smrg
438a96d7823Smrg    /* stick it on the end of the list (since its expected last) */
439a96d7823Smrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
440a96d7823Smrg	;
441a96d7823Smrg    *prev = blockrec;
442a96d7823Smrg
443a96d7823Smrg    return blockrec;
444a96d7823Smrg}
445a96d7823Smrg
446a96d7823Smrgstatic void
447a96d7823Smrg_fs_set_pending_reply (FSFpePtr conn)
448a96d7823Smrg{
449a96d7823Smrg    FSBlockDataPtr  blockrec;
450a96d7823Smrg
451a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
452a96d7823Smrg	if (blockrec->errcode == StillWorking)
453a96d7823Smrg	    break;
454a96d7823Smrg    if (blockrec)
455a96d7823Smrg    {
456a96d7823Smrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
457a96d7823Smrg	_fs_mark_block (conn, FS_PENDING_REPLY);
458a96d7823Smrg    }
459a96d7823Smrg    else
460a96d7823Smrg	_fs_unmark_block (conn, FS_PENDING_REPLY);
461a96d7823Smrg}
462a96d7823Smrg
463a96d7823Smrgstatic void
464a96d7823Smrg_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
465a96d7823Smrg{
466a96d7823Smrg    FSBlockDataPtr *prev;
467a96d7823Smrg
468a96d7823Smrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
469a96d7823Smrg	if (*prev == blockrec)
470a96d7823Smrg	{
471a96d7823Smrg	    *prev = blockrec->next;
472a96d7823Smrg	    break;
473a96d7823Smrg	}
474a96d7823Smrg    if (blockrec->type == FS_LOAD_GLYPHS)
475a96d7823Smrg    {
476a96d7823Smrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
477a96d7823Smrg	if (bglyph->num_expected_ranges)
478a96d7823Smrg	    free(bglyph->expected_ranges);
479a96d7823Smrg    }
480a96d7823Smrg    free(blockrec);
481a96d7823Smrg    _fs_set_pending_reply (conn);
482a96d7823Smrg}
483a96d7823Smrg
484a96d7823Smrgstatic void
485a96d7823Smrg_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
486a96d7823Smrg{
487a96d7823Smrg    FSClientsDependingPtr p;
488a96d7823Smrg
489a96d7823Smrg    while ((p = *clients_depending))
490a96d7823Smrg    {
491a96d7823Smrg	*clients_depending = p->next;
492a96d7823Smrg	ClientSignal(p->client);
493a96d7823Smrg	free(p);
494a96d7823Smrg    }
495a96d7823Smrg}
496a96d7823Smrg
497a96d7823Smrgstatic int
498a96d7823Smrg_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
499a96d7823Smrg{
500a96d7823Smrg    FSClientsDependingPtr   new, cd;
501a96d7823Smrg
502a96d7823Smrg    for (; (cd = *clients_depending);
503a96d7823Smrg	 clients_depending = &(*clients_depending)->next)
504a96d7823Smrg    {
505a96d7823Smrg	if (cd->client == client)
506a96d7823Smrg	    return Suspended;
507a96d7823Smrg    }
508a96d7823Smrg
509a96d7823Smrg    new = malloc (sizeof (FSClientsDependingRec));
510a96d7823Smrg    if (!new)
511a96d7823Smrg	return BadAlloc;
512a96d7823Smrg
513a96d7823Smrg    new->client = client;
514a96d7823Smrg    new->next = 0;
515a96d7823Smrg    *clients_depending = new;
516a96d7823Smrg    return Suspended;
517a96d7823Smrg}
518a96d7823Smrg
519a96d7823Smrgstatic void
520a96d7823Smrgconn_start_listening(FSFpePtr conn)
521a96d7823Smrg{
522a96d7823Smrg    if (!conn->fs_listening) {
523a96d7823Smrg	add_fs_fd(conn->fs_fd, fs_fd_handler, conn->fpe);
524a96d7823Smrg	conn->fs_listening = TRUE;
525a96d7823Smrg    }
526a96d7823Smrg}
527a96d7823Smrg
528a96d7823Smrgstatic void
529a96d7823Smrgconn_stop_listening(FSFpePtr conn)
530a96d7823Smrg{
531a96d7823Smrg    if (conn->fs_listening) {
532a96d7823Smrg	remove_fs_fd(conn->fs_fd);
533a96d7823Smrg	conn->fs_listening = FALSE;
534a96d7823Smrg    }
535a96d7823Smrg}
536a96d7823Smrg
537a96d7823Smrg/*
538a96d7823Smrg * When a request is aborted due to a font server failure,
539a96d7823Smrg * signal any depending clients to restart their dependant
540a96d7823Smrg * requests
541a96d7823Smrg */
542a96d7823Smrgstatic void
543a96d7823Smrg_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
544a96d7823Smrg{
545a96d7823Smrg    switch(blockrec->type) {
546a96d7823Smrg    case FS_OPEN_FONT: {
547a96d7823Smrg	FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
548a96d7823Smrg
549a96d7823Smrg	fs_cleanup_bfont (bfont);
550a96d7823Smrg	_fs_signal_clients_depending(&bfont->clients_depending);
551a96d7823Smrg	break;
552a96d7823Smrg    }
553a96d7823Smrg    case FS_LOAD_GLYPHS: {
554a96d7823Smrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
555a96d7823Smrg
556a96d7823Smrg	_fs_clean_aborted_loadglyphs(bglyph->pfont,
557a96d7823Smrg				     bglyph->num_expected_ranges,
558a96d7823Smrg				     bglyph->expected_ranges);
559a96d7823Smrg	_fs_signal_clients_depending(&bglyph->clients_depending);
560a96d7823Smrg	break;
561a96d7823Smrg    }
562a96d7823Smrg    case FS_LIST_FONTS:
563a96d7823Smrg	break;
564a96d7823Smrg    case FS_LIST_WITH_INFO: {
565a96d7823Smrg	FSBlockedListInfoPtr binfo;
566a96d7823Smrg	binfo = (FSBlockedListInfoPtr) blockrec->data;
567a96d7823Smrg	if (binfo->status == FS_LFWI_REPLY)
568a96d7823Smrg	    conn_start_listening(conn);
569a96d7823Smrg	_fs_free_props (&binfo->info);
570a96d7823Smrg    }
571a96d7823Smrg    default:
572a96d7823Smrg	break;
573a96d7823Smrg    }
574a96d7823Smrg}
575a96d7823Smrg
576a96d7823Smrgstatic void
577a96d7823Smrgfs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
578a96d7823Smrg{
579a96d7823Smrg    _fs_clean_aborted_blockrec (conn, blockrec);
580a96d7823Smrg    _fs_remove_block_rec (conn, blockrec);
581a96d7823Smrg}
582a96d7823Smrg
583a96d7823Smrg/*
584a96d7823Smrg * Tell the font server we've failed to complete an open and
585a96d7823Smrg * then unload the partially created font
586a96d7823Smrg */
587a96d7823Smrgstatic void
588a96d7823Smrgfs_cleanup_bfont (FSBlockedFontPtr bfont)
589a96d7823Smrg{
590a96d7823Smrg    FSFontDataRec *fsd;
591a96d7823Smrg
592a96d7823Smrg    if (bfont->pfont)
593a96d7823Smrg    {
594a96d7823Smrg	fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
595a96d7823Smrg
596a96d7823Smrg	/* make sure the FS knows we choked on it */
597a96d7823Smrg	fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
598a96d7823Smrg
599a96d7823Smrg	/*
600a96d7823Smrg	 * Either unload the font if it's being opened for
601a96d7823Smrg	 * the first time, or smash the generation field to
602a96d7823Smrg	 * mark this font as an orphan
603a96d7823Smrg	 */
604a96d7823Smrg	if (!(bfont->flags & FontReopen))
605a96d7823Smrg	{
606a96d7823Smrg	    if (bfont->freeFont)
607a96d7823Smrg		(*bfont->pfont->unload_font) (bfont->pfont);
608a96d7823Smrg#ifdef DEBUG
609a96d7823Smrg	    else
610a96d7823Smrg		fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
611a96d7823Smrg#endif
612a96d7823Smrg	    bfont->pfont = 0;
613a96d7823Smrg	}
614a96d7823Smrg	else
615a96d7823Smrg	    fsd->generation = -1;
616a96d7823Smrg    }
617a96d7823Smrg}
618a96d7823Smrg
619a96d7823Smrg/*
620a96d7823Smrg * Check to see if a complete reply is waiting
621a96d7823Smrg */
622a96d7823Smrgstatic fsGenericReply *
623a96d7823Smrgfs_get_reply (FSFpePtr conn, int *error)
624a96d7823Smrg{
625a96d7823Smrg    char	    *buf;
626a96d7823Smrg    fsGenericReply  *rep;
627a96d7823Smrg    int		    ret;
628a96d7823Smrg
629a96d7823Smrg    /* block if the connection is down or paused in lfwi */
630a96d7823Smrg    if (conn->fs_fd == -1 || !conn->fs_listening)
631a96d7823Smrg    {
632a96d7823Smrg	*error = FSIO_BLOCK;
633a96d7823Smrg	return 0;
634a96d7823Smrg    }
635a96d7823Smrg
636a96d7823Smrg    ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
637a96d7823Smrg    if (ret != FSIO_READY)
638a96d7823Smrg    {
639a96d7823Smrg	*error = FSIO_BLOCK;
640a96d7823Smrg	return 0;
641a96d7823Smrg    }
642a96d7823Smrg
643a96d7823Smrg    rep = (fsGenericReply *) buf;
644a96d7823Smrg
645a96d7823Smrg    /*
646a96d7823Smrg     * Refuse to accept replies longer than a maximum reasonable length,
647a96d7823Smrg     * before we pass to _fs_start_read, since it will try to resize the
648a96d7823Smrg     * incoming connection buffer to this size.  Also avoids integer overflow
649a96d7823Smrg     * on 32-bit systems.
650a96d7823Smrg     */
651a96d7823Smrg    if (rep->length > MAX_REPLY_LENGTH)
652a96d7823Smrg    {
653fd60135fSmrg	ErrorF("fserve: reply length %ld > MAX_REPLY_LENGTH, disconnecting"
654fd60135fSmrg	       " from font server\n", (long)rep->length);
655a96d7823Smrg	_fs_connection_died (conn);
656a96d7823Smrg	*error = FSIO_ERROR;
657a96d7823Smrg	return 0;
658a96d7823Smrg    }
659a96d7823Smrg
660a96d7823Smrg    ret = _fs_start_read (conn, rep->length << 2, &buf);
661a96d7823Smrg    if (ret != FSIO_READY)
662a96d7823Smrg    {
663a96d7823Smrg	*error = FSIO_BLOCK;
664a96d7823Smrg	return 0;
665a96d7823Smrg    }
666a96d7823Smrg
667a96d7823Smrg    *error = FSIO_READY;
668a96d7823Smrg
669a96d7823Smrg    return (fsGenericReply *) buf;
670a96d7823Smrg}
671a96d7823Smrg
672a96d7823Smrgstatic Bool
673a96d7823Smrgfs_reply_ready (FSFpePtr conn)
674a96d7823Smrg{
675a96d7823Smrg    fsGenericReply  *rep;
676a96d7823Smrg
677a96d7823Smrg    if (conn->fs_fd == -1 || !conn->fs_listening)
678a96d7823Smrg	return FALSE;
679a96d7823Smrg    if (fs_data_read (conn) < sizeof (fsGenericReply))
680a96d7823Smrg	return FALSE;
681a96d7823Smrg    rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
682a96d7823Smrg    if (fs_data_read (conn) < rep->length << 2)
683a96d7823Smrg	return FALSE;
684a96d7823Smrg    return TRUE;
685a96d7823Smrg}
686a96d7823Smrg
687a96d7823Smrgstatic void
688a96d7823Smrg_fs_pending_reply (FSFpePtr conn)
689a96d7823Smrg{
690a96d7823Smrg    if (!(conn->blockState & FS_PENDING_REPLY))
691a96d7823Smrg    {
692a96d7823Smrg	_fs_mark_block (conn, FS_PENDING_REPLY);
693a96d7823Smrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
694a96d7823Smrg    }
695a96d7823Smrg}
696a96d7823Smrg
697a96d7823Smrgstatic void
698a96d7823Smrg_fs_prepare_for_reply (FSFpePtr conn)
699a96d7823Smrg{
700a96d7823Smrg    _fs_pending_reply (conn);
701a96d7823Smrg    _fs_flush (conn);
702a96d7823Smrg}
703a96d7823Smrg
704a96d7823Smrg/*
705a96d7823Smrg * Block (for a while) awaiting a complete reply
706a96d7823Smrg */
707a96d7823Smrgstatic int
708a96d7823Smrgfs_await_reply (FSFpePtr conn)
709a96d7823Smrg{
710a96d7823Smrg    int		    ret;
711a96d7823Smrg
712a96d7823Smrg    if (conn->blockState & FS_COMPLETE_REPLY)
713a96d7823Smrg	return FSIO_READY;
714a96d7823Smrg
715a96d7823Smrg    while (!fs_get_reply (conn, &ret))
716a96d7823Smrg    {
717a96d7823Smrg	if (ret != FSIO_BLOCK)
718a96d7823Smrg	    return ret;
719a96d7823Smrg	if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
720a96d7823Smrg	{
721a96d7823Smrg	    _fs_connection_died (conn);
722a96d7823Smrg	    return FSIO_ERROR;
723a96d7823Smrg	}
724a96d7823Smrg    }
725a96d7823Smrg    return FSIO_READY;
726a96d7823Smrg}
727a96d7823Smrg
728a96d7823Smrg/*
729a96d7823Smrg * Process the reply to an OpenBitmapFont request
730a96d7823Smrg */
731a96d7823Smrgstatic int
732a96d7823Smrgfs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
733a96d7823Smrg{
734a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
735a96d7823Smrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
736a96d7823Smrg    fsOpenBitmapFontReply   *rep;
737a96d7823Smrg    FSBlockDataPtr	    blockOrig;
738a96d7823Smrg    FSBlockedFontPtr	    origBfont;
739a96d7823Smrg    int			    ret;
740a96d7823Smrg
741a96d7823Smrg    rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
742a96d7823Smrg    if (!rep || rep->type == FS_Error ||
743a96d7823Smrg	(rep->length != LENGTHOF(fsOpenBitmapFontReply)))
744a96d7823Smrg    {
745a96d7823Smrg	if (ret == FSIO_BLOCK)
746a96d7823Smrg	    return StillWorking;
747a96d7823Smrg	if (rep)
748a96d7823Smrg	    _fs_done_read (conn, rep->length << 2);
749a96d7823Smrg	fs_cleanup_bfont (bfont);
750a96d7823Smrg	_fs_reply_failed (rep, fsOpenBitmapFontReply, "!=");
751a96d7823Smrg	return BadFontName;
752a96d7823Smrg    }
753a96d7823Smrg
754a96d7823Smrg    /* If we're not reopening a font and FS detected a duplicate font
755a96d7823Smrg       open request, replace our reference to the new font with a
756a96d7823Smrg       reference to an existing font (possibly one not finished
757a96d7823Smrg       opening).  If this is a reopen, keep the new font reference...
758a96d7823Smrg       it's got the metrics and extents we read when the font was opened
759a96d7823Smrg       before.  This also gives us the freedom to easily close the font
760a96d7823Smrg       if we we decide (in fs_read_query_info()) that we don't like what
761a96d7823Smrg       we got. */
762a96d7823Smrg
763a96d7823Smrg    if (rep->otherid && !(bfont->flags & FontReopen))
764a96d7823Smrg    {
765a96d7823Smrg	fs_cleanup_bfont (bfont);
766a96d7823Smrg
767a96d7823Smrg	/* Find old font if we're completely done getting it from server. */
768a96d7823Smrg	bfont->pfont = find_old_font(rep->otherid);
769a96d7823Smrg	bfont->freeFont = FALSE;
770a96d7823Smrg	bfont->fontid = rep->otherid;
771a96d7823Smrg	bfont->state = FS_DONE_REPLY;
772a96d7823Smrg	/*
773a96d7823Smrg	 * look for a blocked request to open the same font
774a96d7823Smrg	 */
775a96d7823Smrg	for (blockOrig = conn->blockedRequests;
776a96d7823Smrg		blockOrig;
777a96d7823Smrg		blockOrig = blockOrig->next)
778a96d7823Smrg	{
779a96d7823Smrg	    if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
780a96d7823Smrg	    {
781a96d7823Smrg		origBfont = (FSBlockedFontPtr) blockOrig->data;
782a96d7823Smrg		if (origBfont->fontid == rep->otherid)
783a96d7823Smrg		{
784a96d7823Smrg		    blockrec->depending = blockOrig->depending;
785a96d7823Smrg		    blockOrig->depending = blockrec;
786a96d7823Smrg		    bfont->state = FS_DEPENDING;
787a96d7823Smrg		    bfont->pfont = origBfont->pfont;
788a96d7823Smrg		    break;
789a96d7823Smrg		}
790a96d7823Smrg	    }
791a96d7823Smrg	}
792a96d7823Smrg	if (bfont->pfont == NULL)
793a96d7823Smrg	{
794a96d7823Smrg	    /* XXX - something nasty happened */
795a96d7823Smrg	    ret = BadFontName;
796a96d7823Smrg	}
797a96d7823Smrg	else
798a96d7823Smrg	    ret = AccessDone;
799a96d7823Smrg    }
800a96d7823Smrg    else
801a96d7823Smrg    {
802a96d7823Smrg	bfont->pfont->info.cachable = rep->cachable != 0;
803a96d7823Smrg	bfont->state = FS_INFO_REPLY;
804a96d7823Smrg	/*
805a96d7823Smrg	 * Reset the blockrec for the next reply
806a96d7823Smrg	 */
807a96d7823Smrg	blockrec->sequenceNumber = bfont->queryInfoSequence;
808a96d7823Smrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
809a96d7823Smrg	ret = StillWorking;
810a96d7823Smrg    }
811a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
812a96d7823Smrg    return ret;
813a96d7823Smrg}
814a96d7823Smrg
815a96d7823Smrgstatic Bool
816a96d7823Smrgfs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
817a96d7823Smrg{
818a96d7823Smrg    int	    i;
819a96d7823Smrg
820a96d7823Smrg    if (pInfo1->firstCol != pInfo2->firstCol ||
821a96d7823Smrg	pInfo1->lastCol != pInfo2->lastCol ||
822a96d7823Smrg	pInfo1->firstRow != pInfo2->firstRow ||
823a96d7823Smrg	pInfo1->lastRow != pInfo2->lastRow ||
824a96d7823Smrg	pInfo1->defaultCh != pInfo2->defaultCh ||
825a96d7823Smrg	pInfo1->noOverlap != pInfo2->noOverlap ||
826a96d7823Smrg	pInfo1->terminalFont != pInfo2->terminalFont ||
827a96d7823Smrg	pInfo1->constantMetrics != pInfo2->constantMetrics ||
828a96d7823Smrg	pInfo1->constantWidth != pInfo2->constantWidth ||
829a96d7823Smrg	pInfo1->inkInside != pInfo2->inkInside ||
830a96d7823Smrg	pInfo1->inkMetrics != pInfo2->inkMetrics ||
831a96d7823Smrg	pInfo1->allExist != pInfo2->allExist ||
832a96d7823Smrg	pInfo1->drawDirection != pInfo2->drawDirection ||
833a96d7823Smrg	pInfo1->cachable != pInfo2->cachable ||
834a96d7823Smrg	pInfo1->anamorphic != pInfo2->anamorphic ||
835a96d7823Smrg	pInfo1->maxOverlap != pInfo2->maxOverlap ||
836a96d7823Smrg	pInfo1->fontAscent != pInfo2->fontAscent ||
837a96d7823Smrg	pInfo1->fontDescent != pInfo2->fontDescent ||
838a96d7823Smrg	pInfo1->nprops != pInfo2->nprops)
839a96d7823Smrg	return FALSE;
840a96d7823Smrg
841a96d7823Smrg#define MATCH(xci1, xci2) \
842a96d7823Smrg    (((xci1).leftSideBearing == (xci2).leftSideBearing) && \
843a96d7823Smrg     ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
844a96d7823Smrg     ((xci1).characterWidth == (xci2).characterWidth) && \
845a96d7823Smrg     ((xci1).ascent == (xci2).ascent) && \
846a96d7823Smrg     ((xci1).descent == (xci2).descent) && \
847a96d7823Smrg     ((xci1).attributes == (xci2).attributes))
848a96d7823Smrg
849a96d7823Smrg    if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
850a96d7823Smrg	!MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
851a96d7823Smrg	!MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
852a96d7823Smrg	!MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
853a96d7823Smrg	return FALSE;
854a96d7823Smrg
855a96d7823Smrg#undef MATCH
856a96d7823Smrg
857a96d7823Smrg    for (i = 0; i < pInfo1->nprops; i++)
858a96d7823Smrg	if (pInfo1->isStringProp[i] !=
859a96d7823Smrg		pInfo2->isStringProp[i] ||
860a96d7823Smrg	    pInfo1->props[i].name !=
861a96d7823Smrg		pInfo2->props[i].name ||
862a96d7823Smrg	    pInfo1->props[i].value !=
863a96d7823Smrg		pInfo2->props[i].value)
864a96d7823Smrg	{
865a96d7823Smrg	    return FALSE;
866a96d7823Smrg	}
867a96d7823Smrg    return TRUE;
868a96d7823Smrg}
869a96d7823Smrg
870a96d7823Smrgstatic int
871a96d7823Smrgfs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
872a96d7823Smrg{
873a96d7823Smrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
874a96d7823Smrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
875a96d7823Smrg    fsQueryXInfoReply	*rep;
876a96d7823Smrg    char		*buf;
877a96d7823Smrg    long		bufleft; /* length of reply left to use */
878a96d7823Smrg    fsPropInfo		*pi;
879a96d7823Smrg    fsPropOffset	*po;
880a96d7823Smrg    pointer		pd;
881a96d7823Smrg    FontInfoPtr		pInfo;
882a96d7823Smrg    FontInfoRec		tempInfo;
883a96d7823Smrg    int			err;
884a96d7823Smrg    int			ret;
885a96d7823Smrg
886a96d7823Smrg    rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
887a96d7823Smrg    if (!rep || rep->type == FS_Error ||
888a96d7823Smrg	(rep->length < LENGTHOF(fsQueryXInfoReply)))
889a96d7823Smrg    {
890a96d7823Smrg	if (ret == FSIO_BLOCK)
891a96d7823Smrg	    return StillWorking;
892a96d7823Smrg	if (rep)
893a96d7823Smrg	    _fs_done_read (conn, rep->length << 2);
894a96d7823Smrg	fs_cleanup_bfont (bfont);
895a96d7823Smrg	_fs_reply_failed (rep, fsQueryXInfoReply, "<");
896a96d7823Smrg	return BadFontName;
897a96d7823Smrg    }
898a96d7823Smrg
899a96d7823Smrg    /* If this is a reopen, accumulate the query info into a dummy
900a96d7823Smrg       font and compare to our original data. */
901a96d7823Smrg    if (bfont->flags & FontReopen)
902a96d7823Smrg	pInfo = &tempInfo;
903a96d7823Smrg    else
904a96d7823Smrg	pInfo = &bfont->pfont->info;
905a96d7823Smrg
906a96d7823Smrg    buf = (char *) rep;
907a96d7823Smrg    buf += SIZEOF(fsQueryXInfoReply);
908a96d7823Smrg
909a96d7823Smrg    bufleft = rep->length << 2;
910a96d7823Smrg    bufleft -= SIZEOF(fsQueryXInfoReply);
911a96d7823Smrg
912a96d7823Smrg    /* move the data over */
913a96d7823Smrg    fsUnpack_XFontInfoHeader(rep, pInfo);
914a96d7823Smrg
915a96d7823Smrg    /* compute accelerators */
916a96d7823Smrg    _fs_init_fontinfo(conn, pInfo);
917a96d7823Smrg
918a96d7823Smrg    /* Compute offsets into the reply */
919a96d7823Smrg    if (bufleft < SIZEOF(fsPropInfo))
920a96d7823Smrg    {
921a96d7823Smrg	ret = -1;
922a96d7823Smrg#ifdef DEBUG
923a96d7823Smrg	fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n",
924a96d7823Smrg		bufleft);
925a96d7823Smrg#endif
926a96d7823Smrg	goto bail;
927a96d7823Smrg    }
928a96d7823Smrg    pi = (fsPropInfo *) buf;
929a96d7823Smrg    buf += SIZEOF (fsPropInfo);
930a96d7823Smrg    bufleft -= SIZEOF(fsPropInfo);
931a96d7823Smrg
932a96d7823Smrg    if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets)
933a96d7823Smrg    {
934a96d7823Smrg	ret = -1;
935a96d7823Smrg#ifdef DEBUG
936a96d7823Smrg	fprintf(stderr,
937c7b4381aSmrg		"fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %u\n",
938c7b4381aSmrg		bufleft, (unsigned) pi->num_offsets);
939a96d7823Smrg#endif
940a96d7823Smrg	goto bail;
941a96d7823Smrg    }
942a96d7823Smrg    po = (fsPropOffset *) buf;
943a96d7823Smrg    buf += pi->num_offsets * SIZEOF(fsPropOffset);
944a96d7823Smrg    bufleft -= pi->num_offsets * SIZEOF(fsPropOffset);
945a96d7823Smrg
946a96d7823Smrg    if (bufleft < pi->data_len)
947a96d7823Smrg    {
948a96d7823Smrg	ret = -1;
949a96d7823Smrg#ifdef DEBUG
950a96d7823Smrg	fprintf(stderr,
951c7b4381aSmrg		"fsQueryXInfo: bufleft (%ld) < data_len (%u)\n",
952c7b4381aSmrg		bufleft, (unsigned) pi->data_len);
953a96d7823Smrg#endif
954a96d7823Smrg	goto bail;
955a96d7823Smrg    }
956a96d7823Smrg    pd = (pointer) buf;
957a96d7823Smrg    buf += pi->data_len;
958a96d7823Smrg    bufleft -= pi->data_len;
959a96d7823Smrg
960a96d7823Smrg    /* convert the properties and step over the reply */
961a96d7823Smrg    ret = _fs_convert_props(pi, po, pd, pInfo);
962a96d7823Smrg  bail:
963a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
964a96d7823Smrg
965a96d7823Smrg    if (ret == -1)
966a96d7823Smrg    {
967a96d7823Smrg	fs_cleanup_bfont (bfont);
968a96d7823Smrg	return AllocError;
969a96d7823Smrg    }
970a96d7823Smrg
971a96d7823Smrg    if (bfont->flags & FontReopen)
972a96d7823Smrg    {
973a96d7823Smrg	/* We're reopening a font that we lost because of a downed
974a96d7823Smrg	   connection.  In the interest of avoiding corruption from
975a96d7823Smrg	   opening a different font than the old one (we already have
976a96d7823Smrg	   its metrics, extents, and probably some of its glyphs),
977a96d7823Smrg	   verify that the metrics and properties all match.  */
978a96d7823Smrg
979a96d7823Smrg	if (fs_fonts_match (pInfo, &bfont->pfont->info))
980a96d7823Smrg	{
981a96d7823Smrg	    err = Successful;
982a96d7823Smrg	    bfont->state = FS_DONE_REPLY;
983a96d7823Smrg	}
984a96d7823Smrg	else
985a96d7823Smrg	{
986a96d7823Smrg	    fs_cleanup_bfont (bfont);
987a96d7823Smrg	    err = BadFontName;
988a96d7823Smrg	}
989a96d7823Smrg	_fs_free_props (pInfo);
990a96d7823Smrg
991a96d7823Smrg	return err;
992a96d7823Smrg    }
993a96d7823Smrg
994a96d7823Smrg    /*
995a96d7823Smrg     * Ask for terminal format fonts if possible
996a96d7823Smrg     */
997a96d7823Smrg    if (bfont->pfont->info.terminalFont)
998a96d7823Smrg	bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
999a96d7823Smrg			 BitmapFormatImageRectMax);
1000a96d7823Smrg
1001a96d7823Smrg    /*
1002a96d7823Smrg     * Figure out if the whole font should get loaded right now.
1003a96d7823Smrg     */
1004a96d7823Smrg    if (glyphCachingMode == CACHING_OFF ||
1005a96d7823Smrg	(glyphCachingMode == CACHE_16_BIT_GLYPHS
1006a96d7823Smrg	 && !bfont->pfont->info.lastRow))
1007a96d7823Smrg    {
1008a96d7823Smrg	bfont->flags |= FontLoadAll;
1009a96d7823Smrg    }
1010a96d7823Smrg
1011a96d7823Smrg    /*
1012a96d7823Smrg     * Ready to send the query bitmaps; the terminal font bit has
1013a96d7823Smrg     * been computed and glyphCaching has been considered
1014a96d7823Smrg     */
1015a96d7823Smrg    if (bfont->flags & FontLoadBitmaps)
1016a96d7823Smrg    {
1017a96d7823Smrg	fs_send_query_bitmaps (fpe, blockrec);
1018a96d7823Smrg	_fs_flush (conn);
1019a96d7823Smrg    }
1020a96d7823Smrg
1021a96d7823Smrg    bfont->state = FS_EXTENT_REPLY;
1022a96d7823Smrg
1023a96d7823Smrg    /*
1024a96d7823Smrg     * Reset the blockrec for the next reply
1025a96d7823Smrg     */
1026a96d7823Smrg    blockrec->sequenceNumber = bfont->queryExtentsSequence;
1027a96d7823Smrg    conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
1028a96d7823Smrg
1029a96d7823Smrg    return StillWorking;
1030a96d7823Smrg}
1031a96d7823Smrg
1032a96d7823Smrgstatic int
1033a96d7823Smrgfs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1034a96d7823Smrg{
1035a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
1036a96d7823Smrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1037a96d7823Smrg    FSFontDataPtr	    fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
1038a96d7823Smrg    FSFontPtr		    fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
1039a96d7823Smrg    fsQueryXExtents16Reply  *rep;
1040a96d7823Smrg    char		    *buf;
1041a96d7823Smrg    int			    i;
1042a96d7823Smrg    int			    numExtents;
1043a96d7823Smrg    int			    numInfos;
1044a96d7823Smrg    int			    ret;
1045a96d7823Smrg    Bool		    haveInk = FALSE; /* need separate ink metrics? */
1046a96d7823Smrg    CharInfoPtr		    ci, pCI;
1047a96d7823Smrg    char		    *fsci;
1048a96d7823Smrg    fsXCharInfo		    fscilocal;
1049a96d7823Smrg    FontInfoRec		    *fi = &bfont->pfont->info;
1050a96d7823Smrg
1051a96d7823Smrg    rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
1052a96d7823Smrg    if (!rep || rep->type == FS_Error ||
1053a96d7823Smrg	(rep->length < LENGTHOF(fsQueryXExtents16Reply)))
1054a96d7823Smrg    {
1055a96d7823Smrg	if (ret == FSIO_BLOCK)
1056a96d7823Smrg	    return StillWorking;
1057a96d7823Smrg	if (rep)
1058a96d7823Smrg	    _fs_done_read (conn, rep->length << 2);
1059a96d7823Smrg	fs_cleanup_bfont (bfont);
1060a96d7823Smrg	_fs_reply_failed (rep, fsQueryXExtents16Reply, "<");
1061a96d7823Smrg	return BadFontName;
1062a96d7823Smrg    }
1063a96d7823Smrg
1064a96d7823Smrg    /* move the data over */
1065a96d7823Smrg    /* need separate inkMetrics for fixed font server protocol version */
1066a96d7823Smrg    numExtents = rep->num_extents;
1067a96d7823Smrg    numInfos = numExtents;
1068a96d7823Smrg    if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
1069a96d7823Smrg    {
1070a96d7823Smrg	numInfos *= 2;
1071a96d7823Smrg	haveInk = TRUE;
1072a96d7823Smrg    }
1073a96d7823Smrg    if (numInfos >= (INT_MAX / sizeof(CharInfoRec))) {
1074a96d7823Smrg#ifdef DEBUG
1075a96d7823Smrg	fprintf(stderr,
1076a96d7823Smrg		"fsQueryXExtents16: numInfos (%d) >= %ld\n",
1077a96d7823Smrg		numInfos, (INT_MAX / sizeof(CharInfoRec)));
1078a96d7823Smrg#endif
1079a96d7823Smrg	pCI = NULL;
1080a96d7823Smrg    }
1081a96d7823Smrg    else if (numExtents > ((rep->length - LENGTHOF(fsQueryXExtents16Reply))
1082a96d7823Smrg			    / LENGTHOF(fsXCharInfo))) {
1083a96d7823Smrg#ifdef DEBUG
1084a96d7823Smrg	fprintf(stderr,
1085c7b4381aSmrg		"fsQueryXExtents16: numExtents (%d) > (%u - %d) / %d\n",
1086c7b4381aSmrg		numExtents, (unsigned) rep->length,
1087a96d7823Smrg		LENGTHOF(fsQueryXExtents16Reply), LENGTHOF(fsXCharInfo));
1088a96d7823Smrg#endif
1089a96d7823Smrg	pCI = NULL;
1090a96d7823Smrg    }
1091a96d7823Smrg    else
1092c7b4381aSmrg	pCI = mallocarray(numInfos, sizeof(CharInfoRec));
1093a96d7823Smrg
1094a96d7823Smrg    if (!pCI)
1095a96d7823Smrg    {
1096a96d7823Smrg	_fs_done_read (conn, rep->length << 2);
1097a96d7823Smrg	fs_cleanup_bfont(bfont);
1098a96d7823Smrg	return AllocError;
1099a96d7823Smrg    }
1100a96d7823Smrg    fsfont->encoding = pCI;
1101a96d7823Smrg    if (haveInk)
1102a96d7823Smrg	fsfont->inkMetrics = pCI + numExtents;
1103a96d7823Smrg    else
1104a96d7823Smrg        fsfont->inkMetrics = pCI;
1105a96d7823Smrg
1106a96d7823Smrg    buf = (char *) rep;
1107a96d7823Smrg    buf += SIZEOF (fsQueryXExtents16Reply);
1108a96d7823Smrg    fsci = buf;
1109a96d7823Smrg
1110a96d7823Smrg    fsd->glyphs_to_get = 0;
1111a96d7823Smrg    ci = fsfont->inkMetrics;
1112a96d7823Smrg    for (i = 0; i < numExtents; i++)
1113a96d7823Smrg    {
1114a96d7823Smrg	memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
1115a96d7823Smrg	_fs_convert_char_info(&fscilocal, &ci->metrics);
1116a96d7823Smrg	/* Bounds check. */
1117a96d7823Smrg	if (ci->metrics.ascent > fi->maxbounds.ascent)
1118a96d7823Smrg	{
1119a96d7823Smrg	    ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
1120a96d7823Smrg		   fpe->name, fsd->name,
1121a96d7823Smrg		   ci->metrics.ascent, fi->maxbounds.ascent);
1122a96d7823Smrg	    ci->metrics.ascent = fi->maxbounds.ascent;
1123a96d7823Smrg	}
1124a96d7823Smrg	if (ci->metrics.descent > fi->maxbounds.descent)
1125a96d7823Smrg	{
1126a96d7823Smrg	    ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
1127a96d7823Smrg		   fpe->name, fsd->name,
1128a96d7823Smrg		   ci->metrics.descent, fi->maxbounds.descent);
1129a96d7823Smrg	    ci->metrics.descent = fi->maxbounds.descent;
1130a96d7823Smrg	}
1131a96d7823Smrg	fsci = fsci + SIZEOF(fsXCharInfo);
1132a96d7823Smrg	/* Initialize the bits field for later glyph-caching use */
1133a96d7823Smrg	if (NONZEROMETRICS(&ci->metrics))
1134a96d7823Smrg	{
1135a96d7823Smrg	    if (!haveInk &&
1136a96d7823Smrg		(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
1137a96d7823Smrg		 ci->metrics.ascent == -ci->metrics.descent))
1138a96d7823Smrg		pCI[i].bits = &_fs_glyph_zero_length;
1139a96d7823Smrg	    else
1140a96d7823Smrg	    {
1141a96d7823Smrg		pCI[i].bits = &_fs_glyph_undefined;
1142a96d7823Smrg		fsd->glyphs_to_get++;
1143a96d7823Smrg	    }
1144a96d7823Smrg	}
1145a96d7823Smrg	else
1146a96d7823Smrg	    pCI[i].bits = (char *)0;
1147a96d7823Smrg	ci++;
1148a96d7823Smrg    }
1149a96d7823Smrg
1150a96d7823Smrg    /* Done with reply */
1151a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
1152a96d7823Smrg
1153a96d7823Smrg    /* build bitmap metrics, ImageRectMax style */
1154a96d7823Smrg    if (haveInk)
1155a96d7823Smrg    {
1156a96d7823Smrg	CharInfoPtr ii;
1157a96d7823Smrg
1158a96d7823Smrg	ci = fsfont->encoding;
1159a96d7823Smrg	ii = fsfont->inkMetrics;
1160a96d7823Smrg	for (i = 0; i < numExtents; i++, ci++, ii++)
1161a96d7823Smrg	{
1162a96d7823Smrg	    if (NONZEROMETRICS(&ii->metrics))
1163a96d7823Smrg	    {
1164a96d7823Smrg		ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
1165a96d7823Smrg		ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
1166a96d7823Smrg		ci->metrics.ascent = FONT_MAX_ASCENT(fi);
1167a96d7823Smrg		ci->metrics.descent = FONT_MAX_DESCENT(fi);
1168a96d7823Smrg		ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
1169a96d7823Smrg		ci->metrics.attributes = ii->metrics.attributes;
1170a96d7823Smrg	    }
1171a96d7823Smrg	    else
1172a96d7823Smrg	    {
1173a96d7823Smrg		ci->metrics = ii->metrics;
1174a96d7823Smrg	    }
1175a96d7823Smrg	    /* Bounds check. */
1176a96d7823Smrg	    if (ci->metrics.ascent > fi->maxbounds.ascent)
1177a96d7823Smrg	    {
1178a96d7823Smrg		ErrorF("fserve: warning: %s %s ascent (%d) "
1179a96d7823Smrg		       "> maxascent (%d)\n",
1180a96d7823Smrg		       fpe->name, fsd->name,
1181a96d7823Smrg		       ci->metrics.ascent, fi->maxbounds.ascent);
1182a96d7823Smrg		ci->metrics.ascent = fi->maxbounds.ascent;
1183a96d7823Smrg	    }
1184a96d7823Smrg	    if (ci->metrics.descent > fi->maxbounds.descent)
1185a96d7823Smrg	    {
1186a96d7823Smrg		ErrorF("fserve: warning: %s %s descent (%d) "
1187a96d7823Smrg		       "> maxdescent (%d)\n",
1188a96d7823Smrg		       fpe->name, fsd->name,
1189a96d7823Smrg		       ci->metrics.descent, fi->maxbounds.descent);
1190a96d7823Smrg		ci->metrics.descent = fi->maxbounds.descent;
1191a96d7823Smrg	    }
1192a96d7823Smrg	}
1193a96d7823Smrg    }
1194a96d7823Smrg    {
1195a96d7823Smrg	unsigned int r, c, numCols, firstCol;
1196a96d7823Smrg
1197a96d7823Smrg	firstCol = bfont->pfont->info.firstCol;
1198a96d7823Smrg	numCols = bfont->pfont->info.lastCol - firstCol + 1;
1199a96d7823Smrg	c = bfont->pfont->info.defaultCh;
1200a96d7823Smrg	fsfont->pDefault = 0;
1201a96d7823Smrg	if (bfont->pfont->info.lastRow)
1202a96d7823Smrg	{
1203a96d7823Smrg	    r = c >> 8;
1204a96d7823Smrg	    r -= bfont->pfont->info.firstRow;
1205a96d7823Smrg	    c &= 0xff;
1206a96d7823Smrg	    c -= firstCol;
1207a96d7823Smrg	    if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
1208a96d7823Smrg		c < numCols)
1209a96d7823Smrg		fsfont->pDefault = &pCI[r * numCols + c];
1210a96d7823Smrg	}
1211a96d7823Smrg	else
1212a96d7823Smrg	{
1213a96d7823Smrg	    c -= firstCol;
1214a96d7823Smrg	    if (c < numCols)
1215a96d7823Smrg		fsfont->pDefault = &pCI[c];
1216a96d7823Smrg	}
1217a96d7823Smrg    }
1218a96d7823Smrg    bfont->state = FS_GLYPHS_REPLY;
1219a96d7823Smrg
1220a96d7823Smrg    if (bfont->flags & FontLoadBitmaps)
1221a96d7823Smrg    {
1222a96d7823Smrg	/*
1223a96d7823Smrg	 * Reset the blockrec for the next reply
1224a96d7823Smrg	 */
1225a96d7823Smrg	blockrec->sequenceNumber = bfont->queryBitmapsSequence;
1226a96d7823Smrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
1227a96d7823Smrg	return StillWorking;
1228a96d7823Smrg    }
1229a96d7823Smrg    return Successful;
1230a96d7823Smrg}
1231a96d7823Smrg
1232a96d7823Smrg#ifdef DEBUG
1233a96d7823Smrgstatic const char *fs_open_states[] = {
1234a96d7823Smrg    "OPEN_REPLY  ",
1235a96d7823Smrg    "INFO_REPLY  ",
1236a96d7823Smrg    "EXTENT_REPLY",
1237a96d7823Smrg    "GLYPHS_REPLY",
1238a96d7823Smrg    "DONE_REPLY  ",
1239a96d7823Smrg    "DEPENDING   ",
1240a96d7823Smrg};
1241a96d7823Smrg#endif
1242a96d7823Smrg
1243a96d7823Smrgstatic int
1244a96d7823Smrgfs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1245a96d7823Smrg{
1246a96d7823Smrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
1247a96d7823Smrg    int			err;
1248a96d7823Smrg
1249a96d7823Smrg#ifdef DEBUG
1250a96d7823Smrg    fprintf (stderr, "fs_do_open_font state %s %s\n",
1251a96d7823Smrg	     fs_open_states[bfont->state],
1252a96d7823Smrg	     ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
1253a96d7823Smrg#endif
1254a96d7823Smrg    err = BadFontName;
1255a96d7823Smrg    switch (bfont->state) {
1256a96d7823Smrg    case FS_OPEN_REPLY:
1257a96d7823Smrg	err = fs_read_open_font(fpe, blockrec);
1258a96d7823Smrg	if (err != StillWorking) {	/* already loaded, or error */
1259a96d7823Smrg	    /* if font's already loaded, massage error code */
1260a96d7823Smrg	    switch (bfont->state) {
1261a96d7823Smrg	    case FS_DONE_REPLY:
1262a96d7823Smrg		err = Successful;
1263a96d7823Smrg		break;
1264a96d7823Smrg	    case FS_DEPENDING:
1265a96d7823Smrg		err = StillWorking;
1266a96d7823Smrg		break;
1267a96d7823Smrg	    }
1268a96d7823Smrg	}
1269a96d7823Smrg	break;
1270a96d7823Smrg    case FS_INFO_REPLY:
1271a96d7823Smrg	err = fs_read_query_info(fpe, blockrec);
1272a96d7823Smrg	break;
1273a96d7823Smrg    case FS_EXTENT_REPLY:
1274a96d7823Smrg	err = fs_read_extent_info(fpe, blockrec);
1275a96d7823Smrg	break;
1276a96d7823Smrg    case FS_GLYPHS_REPLY:
1277a96d7823Smrg	if (bfont->flags & FontLoadBitmaps)
1278a96d7823Smrg	    err = fs_read_glyphs(fpe, blockrec);
1279a96d7823Smrg	break;
1280a96d7823Smrg    case FS_DEPENDING:		/* can't happen */
1281a96d7823Smrg    default:
1282a96d7823Smrg	break;
1283a96d7823Smrg    }
1284a96d7823Smrg#ifdef DEBUG
1285a96d7823Smrg    fprintf (stderr, "fs_do_open_font err %d\n", err);
1286a96d7823Smrg#endif
1287a96d7823Smrg    if (err != StillWorking)
1288a96d7823Smrg    {
1289a96d7823Smrg	bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1290a96d7823Smrg	while ((blockrec = blockrec->depending))
1291a96d7823Smrg	{
1292a96d7823Smrg	    bfont = (FSBlockedFontPtr) blockrec->data;
1293a96d7823Smrg	    bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1294a96d7823Smrg	}
1295a96d7823Smrg    }
1296a96d7823Smrg    return err;
1297a96d7823Smrg}
1298a96d7823Smrg
1299a96d7823Smrgvoid
1300a96d7823Smrg_fs_mark_block (FSFpePtr conn, CARD32 mask)
1301a96d7823Smrg{
1302a96d7823Smrg    conn->blockState |= mask;
1303a96d7823Smrg    fs_blockState |= mask;
1304a96d7823Smrg}
1305a96d7823Smrg
1306a96d7823Smrgvoid
1307a96d7823Smrg_fs_unmark_block (FSFpePtr conn, CARD32 mask)
1308a96d7823Smrg{
1309a96d7823Smrg    FSFpePtr	c;
1310a96d7823Smrg
1311a96d7823Smrg    if (conn->blockState & mask)
1312a96d7823Smrg    {
1313a96d7823Smrg	conn->blockState &= ~mask;
1314a96d7823Smrg	fs_blockState = 0;
1315a96d7823Smrg	for (c = fs_fpes; c; c = c->next)
1316a96d7823Smrg	    fs_blockState |= c->blockState;
1317a96d7823Smrg    }
1318a96d7823Smrg}
1319a96d7823Smrg
1320a96d7823Smrg/* ARGSUSED */
1321a96d7823Smrgstatic void
1322a96d7823Smrgfs_block_handler(void *wt)
1323a96d7823Smrg{
1324a96d7823Smrg    CARD32	now, earliest, wakeup;
1325a96d7823Smrg    int		soonest;
1326a96d7823Smrg    FSFpePtr    conn;
1327a96d7823Smrg
1328a96d7823Smrg    /*
1329a96d7823Smrg     * Flush all pending output
1330a96d7823Smrg     */
1331a96d7823Smrg    if (fs_blockState & FS_PENDING_WRITE)
1332a96d7823Smrg	for (conn = fs_fpes; conn; conn = conn->next)
1333a96d7823Smrg	    if (conn->blockState & FS_PENDING_WRITE)
1334a96d7823Smrg		_fs_flush (conn);
1335a96d7823Smrg    /*
1336a96d7823Smrg     * Check for any fpe with a complete reply, set sleep time to zero
1337a96d7823Smrg     */
1338a96d7823Smrg    if (fs_blockState & FS_COMPLETE_REPLY)
1339a96d7823Smrg	adjust_fs_wait_for_delay(wt, 0);
1340a96d7823Smrg    /*
1341a96d7823Smrg     * Walk through fpe list computing sleep time
1342a96d7823Smrg     */
1343a96d7823Smrg    else if (fs_blockState & (FS_BROKEN_WRITE|
1344a96d7823Smrg			      FS_BROKEN_CONNECTION|
1345a96d7823Smrg			      FS_PENDING_REPLY|
1346a96d7823Smrg			      FS_RECONNECTING))
1347a96d7823Smrg    {
1348a96d7823Smrg	now = GetTimeInMillis ();
1349a96d7823Smrg	earliest = now + 10000000;
1350a96d7823Smrg	for (conn = fs_fpes; conn; conn = conn->next)
1351a96d7823Smrg	{
1352a96d7823Smrg	    if (conn->blockState & FS_RECONNECTING)
1353a96d7823Smrg	    {
1354a96d7823Smrg		wakeup = conn->blockedConnectTime;
1355a96d7823Smrg		if (TimeCmp (wakeup, <, earliest))
1356a96d7823Smrg		    earliest = wakeup;
1357a96d7823Smrg	    }
1358a96d7823Smrg	    if (conn->blockState & FS_BROKEN_CONNECTION)
1359a96d7823Smrg	    {
1360a96d7823Smrg		wakeup = conn->brokenConnectionTime;
1361a96d7823Smrg		if (TimeCmp (wakeup, <, earliest))
1362a96d7823Smrg		    earliest = wakeup;
1363a96d7823Smrg	    }
1364a96d7823Smrg	    if (conn->blockState & FS_BROKEN_WRITE)
1365a96d7823Smrg	    {
1366a96d7823Smrg		wakeup = conn->brokenWriteTime;
1367a96d7823Smrg		if (TimeCmp (wakeup, <, earliest))
1368a96d7823Smrg		    earliest = wakeup;
1369a96d7823Smrg	    }
1370a96d7823Smrg	    if (conn->blockState & FS_PENDING_REPLY)
1371a96d7823Smrg	    {
1372a96d7823Smrg		wakeup = conn->blockedReplyTime;
1373a96d7823Smrg		if (TimeCmp (wakeup, <, earliest))
1374a96d7823Smrg		    earliest = wakeup;
1375a96d7823Smrg	    }
1376a96d7823Smrg	}
1377a96d7823Smrg	soonest = earliest - now;
1378a96d7823Smrg	if (soonest < 0)
1379a96d7823Smrg	    soonest = 0;
1380a96d7823Smrg	adjust_fs_wait_for_delay(wt, soonest);
1381a96d7823Smrg    }
1382a96d7823Smrg}
1383a96d7823Smrg
1384a96d7823Smrgstatic void
1385a96d7823Smrgfs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
1386a96d7823Smrg{
1387a96d7823Smrg    if (rep->type == FS_Event && rep->data1 == KeepAlive)
1388a96d7823Smrg    {
1389a96d7823Smrg	fsNoopReq   req;
1390a96d7823Smrg
1391a96d7823Smrg	/* ping it back */
1392a96d7823Smrg	req.reqType = FS_Noop;
1393a96d7823Smrg	req.length = SIZEOF(fsNoopReq) >> 2;
1394a96d7823Smrg	_fs_add_req_log(conn, FS_Noop);
1395a96d7823Smrg	_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
1396a96d7823Smrg    }
1397a96d7823Smrg    /* this should suck up unexpected replies and events */
1398a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
1399a96d7823Smrg}
1400a96d7823Smrg
1401a96d7823Smrgstatic void
1402a96d7823Smrgfs_read_reply (FontPathElementPtr fpe, pointer client)
1403a96d7823Smrg{
1404a96d7823Smrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
1405a96d7823Smrg    FSBlockDataPtr  blockrec;
1406a96d7823Smrg    int		    ret;
1407a96d7823Smrg    int		    err;
1408a96d7823Smrg    fsGenericReply  *rep;
1409a96d7823Smrg
1410a96d7823Smrg    if ((rep = fs_get_reply (conn, &ret)))
1411a96d7823Smrg    {
1412a96d7823Smrg	_fs_add_rep_log (conn, rep);
1413a96d7823Smrg	for (blockrec = conn->blockedRequests;
1414a96d7823Smrg	     blockrec;
1415a96d7823Smrg	     blockrec = blockrec->next)
1416a96d7823Smrg	{
1417a96d7823Smrg	    if (blockrec->sequenceNumber == rep->sequenceNumber)
1418a96d7823Smrg		break;
1419a96d7823Smrg	}
1420a96d7823Smrg	err = Successful;
1421a96d7823Smrg	if (!blockrec)
1422a96d7823Smrg	{
1423a96d7823Smrg	    fs_handle_unexpected(conn, rep);
1424a96d7823Smrg	}
1425a96d7823Smrg	else
1426a96d7823Smrg	{
1427a96d7823Smrg	    /*
1428a96d7823Smrg	     * go read it, and if we're done,
1429a96d7823Smrg	     * wake up the appropriate client
1430a96d7823Smrg	     */
1431a96d7823Smrg	    switch (blockrec->type) {
1432a96d7823Smrg	    case FS_OPEN_FONT:
1433a96d7823Smrg		blockrec->errcode = fs_do_open_font(fpe, blockrec);
1434a96d7823Smrg		break;
1435a96d7823Smrg	    case FS_LOAD_GLYPHS:
1436a96d7823Smrg		blockrec->errcode = fs_read_glyphs(fpe, blockrec);
1437a96d7823Smrg		break;
1438a96d7823Smrg	    case FS_LIST_FONTS:
1439a96d7823Smrg		blockrec->errcode = fs_read_list(fpe, blockrec);
1440a96d7823Smrg		break;
1441a96d7823Smrg	    case FS_LIST_WITH_INFO:
1442a96d7823Smrg		blockrec->errcode = fs_read_list_info(fpe, blockrec);
1443a96d7823Smrg		break;
1444a96d7823Smrg	    default:
1445a96d7823Smrg		break;
1446a96d7823Smrg	    }
1447a96d7823Smrg	    err = blockrec->errcode;
1448a96d7823Smrg	    if (err != StillWorking)
1449a96d7823Smrg	    {
1450a96d7823Smrg		while (blockrec)
1451a96d7823Smrg		{
1452a96d7823Smrg		    blockrec->errcode = err;
1453a96d7823Smrg		    if (client != blockrec->client)
1454a96d7823Smrg			ClientSignal(blockrec->client);
1455a96d7823Smrg		    blockrec = blockrec->depending;
1456a96d7823Smrg		}
1457a96d7823Smrg		_fs_unmark_block (conn, FS_PENDING_REPLY);
1458a96d7823Smrg	    }
1459a96d7823Smrg	}
1460a96d7823Smrg	if (fs_reply_ready (conn))
1461a96d7823Smrg	    _fs_mark_block (conn, FS_COMPLETE_REPLY);
1462a96d7823Smrg	else
1463a96d7823Smrg	    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
1464a96d7823Smrg    }
1465a96d7823Smrg}
1466a96d7823Smrg
1467a96d7823Smrgstatic void
1468a96d7823Smrgfs_fd_handler(int fd, void *data)
1469a96d7823Smrg{
1470a96d7823Smrg    FontPathElementPtr	fpe = data;
1471a96d7823Smrg    FSFpePtr	    	conn = (FSFpePtr) fpe->private;
1472a96d7823Smrg
1473a96d7823Smrg    /*
1474a96d7823Smrg     * Don't continue if the fd is -1 (which will be true when the
1475a96d7823Smrg     * font server terminates
1476a96d7823Smrg     */
1477a96d7823Smrg    if ((conn->blockState & FS_RECONNECTING))
1478a96d7823Smrg	_fs_check_reconnect (conn);
1479a96d7823Smrg    else if ((conn->fs_fd != -1))
1480a96d7823Smrg	fs_read_reply (fpe, 0);
1481a96d7823Smrg}
1482a96d7823Smrg
1483a96d7823Smrgstatic int
1484a96d7823Smrgfs_wakeup(FontPathElementPtr fpe)
1485a96d7823Smrg{
1486a96d7823Smrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
1487a96d7823Smrg
1488a96d7823Smrg    if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
1489a96d7823Smrg	_fs_do_blocked (conn);
1490a96d7823Smrg    if (conn->blockState & FS_COMPLETE_REPLY)
1491a96d7823Smrg	fs_read_reply (fpe, 0);
1492a96d7823Smrg#ifdef DEBUG
1493a96d7823Smrg    {
1494a96d7823Smrg	FSBlockDataPtr	    blockrec;
1495a96d7823Smrg	FSBlockedFontPtr    bfont;
1496a96d7823Smrg	static CARD32	    lastState;
1497a96d7823Smrg	static FSBlockDataPtr	lastBlock;
1498a96d7823Smrg
1499a96d7823Smrg	if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
1500a96d7823Smrg	{
1501a96d7823Smrg	    fprintf (stderr, "  Block State 0x%x\n", (int) conn->blockState);
1502a96d7823Smrg	    lastState = conn->blockState;
1503a96d7823Smrg	    lastBlock = conn->blockedRequests;
1504a96d7823Smrg	}
1505a96d7823Smrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1506a96d7823Smrg	{
1507a96d7823Smrg	    switch (blockrec->type) {
1508a96d7823Smrg	    case FS_OPEN_FONT:
1509a96d7823Smrg		bfont = (FSBlockedFontPtr) blockrec->data;
1510a96d7823Smrg		fprintf (stderr, "  Blocked font errcode %d sequence %d state %s %s\n",
1511a96d7823Smrg			 blockrec->errcode,
1512a96d7823Smrg			 blockrec->sequenceNumber,
1513a96d7823Smrg			 fs_open_states[bfont->state],
1514a96d7823Smrg			 bfont->pfont ?
1515a96d7823Smrg			 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
1516a96d7823Smrg			 "<freed>");
1517a96d7823Smrg		break;
1518a96d7823Smrg	    case FS_LIST_FONTS:
1519a96d7823Smrg		fprintf (stderr, "  Blocked list errcode %d sequence %d\n",
1520a96d7823Smrg			 blockrec->errcode, blockrec->sequenceNumber);
1521a96d7823Smrg		break;
1522a96d7823Smrg	    default:
1523a96d7823Smrg		fprintf (stderr, "  Blocked type %d errcode %d sequence %d\n",
1524a96d7823Smrg			 blockrec->type,
1525a96d7823Smrg			 blockrec->errcode,
1526a96d7823Smrg			 blockrec->sequenceNumber);
1527a96d7823Smrg		break;
1528a96d7823Smrg	    }
1529a96d7823Smrg	}
1530a96d7823Smrg    }
1531a96d7823Smrg#endif
1532a96d7823Smrg    return FALSE;
1533a96d7823Smrg}
1534a96d7823Smrg
1535a96d7823Smrg/*
1536a96d7823Smrg * Notice a dead connection and prepare for reconnect
1537a96d7823Smrg */
1538a96d7823Smrg
1539a96d7823Smrgvoid
1540a96d7823Smrg_fs_connection_died(FSFpePtr conn)
1541a96d7823Smrg{
1542a96d7823Smrg    if (conn->blockState & FS_BROKEN_CONNECTION)
1543a96d7823Smrg	return;
1544a96d7823Smrg    fs_close_conn(conn);
1545a96d7823Smrg    conn->brokenConnectionTime = GetTimeInMillis ();
1546a96d7823Smrg    _fs_mark_block (conn, FS_BROKEN_CONNECTION);
1547a96d7823Smrg    _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
1548a96d7823Smrg}
1549a96d7823Smrg
1550a96d7823Smrg/*
1551a96d7823Smrg * Signal clients that the connection has come back up
1552a96d7823Smrg */
1553a96d7823Smrgstatic int
1554a96d7823Smrg_fs_restart_connection(FSFpePtr conn)
1555a96d7823Smrg{
1556a96d7823Smrg    FSBlockDataPtr block;
1557a96d7823Smrg
1558a96d7823Smrg    _fs_unmark_block (conn, FS_GIVE_UP);
1559a96d7823Smrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
1560a96d7823Smrg    {
1561a96d7823Smrg	if (block->errcode == StillWorking)
1562a96d7823Smrg	{
1563a96d7823Smrg	    ClientSignal(block->client);
1564a96d7823Smrg	    fs_abort_blockrec(conn, block);
1565a96d7823Smrg	}
1566a96d7823Smrg    }
1567a96d7823Smrg    return TRUE;
1568a96d7823Smrg}
1569a96d7823Smrg
1570a96d7823Smrg/*
1571a96d7823Smrg * Declare this font server connection useless
1572a96d7823Smrg */
1573a96d7823Smrgstatic void
1574a96d7823Smrg_fs_giveup (FSFpePtr conn)
1575a96d7823Smrg{
1576a96d7823Smrg    FSBlockDataPtr  block;
1577a96d7823Smrg
1578a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
1579a96d7823Smrg	return;
1580a96d7823Smrg#ifdef DEBUG
1581a96d7823Smrg    fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
1582a96d7823Smrg#endif
1583a96d7823Smrg    _fs_mark_block (conn, FS_GIVE_UP);
1584a96d7823Smrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
1585a96d7823Smrg    {
1586a96d7823Smrg	if (block->errcode == StillWorking)
1587a96d7823Smrg	{
1588a96d7823Smrg	    ClientSignal (block->client);
1589a96d7823Smrg	    fs_abort_blockrec (conn, block);
1590a96d7823Smrg	}
1591a96d7823Smrg    }
1592a96d7823Smrg    if (conn->fs_fd >= 0)
1593a96d7823Smrg	_fs_connection_died (conn);
1594a96d7823Smrg}
1595a96d7823Smrg
1596a96d7823Smrgstatic void
1597a96d7823Smrg_fs_do_blocked (FSFpePtr conn)
1598a96d7823Smrg{
1599a96d7823Smrg    CARD32      now;
1600a96d7823Smrg
1601a96d7823Smrg    now = GetTimeInMillis ();
1602a96d7823Smrg    if ((conn->blockState & FS_PENDING_REPLY) &&
1603a96d7823Smrg	TimeCmp (conn->blockedReplyTime, <=, now))
1604a96d7823Smrg    {
1605a96d7823Smrg	_fs_giveup (conn);
1606a96d7823Smrg    }
1607a96d7823Smrg    else
1608a96d7823Smrg    {
1609a96d7823Smrg	if (conn->blockState & FS_BROKEN_CONNECTION)
1610a96d7823Smrg	{
1611a96d7823Smrg	    /* Try to reconnect broken connections */
1612a96d7823Smrg	    if (TimeCmp (conn->brokenConnectionTime, <=, now))
1613a96d7823Smrg		_fs_start_reconnect (conn);
1614a96d7823Smrg	}
1615a96d7823Smrg	else if (conn->blockState & FS_BROKEN_WRITE)
1616a96d7823Smrg	{
1617a96d7823Smrg	    /* Try to flush blocked connections */
1618a96d7823Smrg	    if (TimeCmp (conn->brokenWriteTime, <=, now))
1619a96d7823Smrg		_fs_flush (conn);
1620a96d7823Smrg	}
1621a96d7823Smrg    }
1622a96d7823Smrg}
1623a96d7823Smrg
1624a96d7823Smrg/*
1625a96d7823Smrg * sends the actual request out
1626a96d7823Smrg */
1627a96d7823Smrg/* ARGSUSED */
1628a96d7823Smrgstatic int
1629a96d7823Smrgfs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1630a96d7823Smrg		  const char *name, int namelen,
1631a96d7823Smrg		  fsBitmapFormat format, fsBitmapFormatMask fmask,
1632a96d7823Smrg		  XID id, FontPtr *ppfont)
1633a96d7823Smrg{
1634a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
1635a96d7823Smrg    FontPtr		    font;
1636a96d7823Smrg    FSBlockDataPtr	    blockrec = NULL;
1637a96d7823Smrg    FSBlockedFontPtr	    bfont;
1638a96d7823Smrg    FSFontDataPtr	    fsd;
1639a96d7823Smrg    fsOpenBitmapFontReq	    openreq;
1640a96d7823Smrg    fsQueryXInfoReq	    inforeq;
1641a96d7823Smrg    fsQueryXExtents16Req    extreq;
1642a96d7823Smrg    int			    err;
1643a96d7823Smrg    unsigned char	    buf[1024];
1644a96d7823Smrg
1645a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
1646a96d7823Smrg	return BadFontName;
1647a96d7823Smrg
1648a96d7823Smrg    if (namelen < 0 || namelen > sizeof (buf) - 1)
1649a96d7823Smrg	return BadFontName;
1650a96d7823Smrg
1651a96d7823Smrg    /*
1652a96d7823Smrg     * Get the font structure put together, either by reusing
1653a96d7823Smrg     * the existing one or creating a new one
1654a96d7823Smrg     */
1655a96d7823Smrg    if (flags & FontReopen)
1656a96d7823Smrg    {
1657a96d7823Smrg	Atom	nameatom, fn = None;
1658a96d7823Smrg	int	i;
1659a96d7823Smrg
1660a96d7823Smrg	font = *ppfont;
1661a96d7823Smrg	fsd = (FSFontDataPtr)font->fpePrivate;
1662a96d7823Smrg	/* This is an attempt to reopen a font.  Did the font have a
1663a96d7823Smrg	   NAME property? */
1664a96d7823Smrg	if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
1665a96d7823Smrg	{
1666a96d7823Smrg	    for (i = 0; i < font->info.nprops; i++)
1667a96d7823Smrg		if (font->info.props[i].name == nameatom &&
1668a96d7823Smrg		    font->info.isStringProp[i])
1669a96d7823Smrg		{
1670a96d7823Smrg		    fn = font->info.props[i].value;
1671a96d7823Smrg		    break;
1672a96d7823Smrg		}
1673a96d7823Smrg	}
1674a96d7823Smrg	if (fn == None || !(name = NameForAtom(fn)))
1675a96d7823Smrg	{
1676a96d7823Smrg	    name = fsd->name;
1677a96d7823Smrg	    namelen = fsd->namelen;
1678a96d7823Smrg	}
1679a96d7823Smrg	else
1680a96d7823Smrg	    namelen = strlen(name);
1681a96d7823Smrg    }
1682a96d7823Smrg    else
1683a96d7823Smrg    {
1684a96d7823Smrg	font = fs_create_font (fpe, name, namelen, format, fmask);
1685a96d7823Smrg	if (!font)
1686a96d7823Smrg	    return AllocError;
1687a96d7823Smrg
1688a96d7823Smrg	fsd = (FSFontDataPtr)font->fpePrivate;
1689a96d7823Smrg    }
1690a96d7823Smrg
1691a96d7823Smrg    /* make a new block record, and add it to the end of the list */
1692a96d7823Smrg    blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
1693a96d7823Smrg    if (!blockrec)
1694a96d7823Smrg    {
1695a96d7823Smrg	if (!(flags & FontReopen))
1696a96d7823Smrg	    (*font->unload_font) (font);
1697a96d7823Smrg	return AllocError;
1698a96d7823Smrg    }
1699a96d7823Smrg
1700a96d7823Smrg    /*
1701a96d7823Smrg     * Must check this before generating any protocol, otherwise we'll
1702a96d7823Smrg     * mess up a reconnect in progress
1703a96d7823Smrg     */
1704a96d7823Smrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
1705a96d7823Smrg    {
1706a96d7823Smrg	_fs_pending_reply (conn);
1707a96d7823Smrg	return Suspended;
1708a96d7823Smrg    }
1709a96d7823Smrg
1710a96d7823Smrg    fsd->generation = conn->generation;
1711a96d7823Smrg
1712a96d7823Smrg    bfont = (FSBlockedFontPtr) blockrec->data;
1713a96d7823Smrg    bfont->fontid = fsd->fontid;
1714a96d7823Smrg    bfont->pfont = font;
1715a96d7823Smrg    bfont->state = FS_OPEN_REPLY;
1716a96d7823Smrg    bfont->flags = flags;
1717a96d7823Smrg    bfont->format = fsd->format;
1718a96d7823Smrg    bfont->clients_depending = (FSClientsDependingPtr)0;
1719a96d7823Smrg    bfont->freeFont = (flags & FontReopen) == 0;
1720a96d7823Smrg
1721a96d7823Smrg    _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
1722a96d7823Smrg    _fs_client_resolution(conn);
1723a96d7823Smrg
1724a96d7823Smrg    /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
1725a96d7823Smrg    buf[0] = (unsigned char) namelen;
1726a96d7823Smrg    memcpy(&buf[1], name, namelen);
1727a96d7823Smrg    openreq.reqType = FS_OpenBitmapFont;
1728a96d7823Smrg    openreq.pad = 0;
1729a96d7823Smrg    openreq.fid = fsd->fontid;
1730a96d7823Smrg    openreq.format_hint = fsd->format;
1731a96d7823Smrg    openreq.format_mask = fsd->fmask;
1732a96d7823Smrg    openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
1733a96d7823Smrg
1734a96d7823Smrg    _fs_add_req_log(conn, FS_OpenBitmapFont);
1735a96d7823Smrg    _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
1736a96d7823Smrg    _fs_write_pad(conn, (char *) buf, namelen + 1);
1737a96d7823Smrg
1738a96d7823Smrg    blockrec->sequenceNumber = conn->current_seq;
1739a96d7823Smrg
1740a96d7823Smrg    inforeq.reqType = FS_QueryXInfo;
1741a96d7823Smrg    inforeq.pad = 0;
1742a96d7823Smrg    inforeq.id = fsd->fontid;
1743a96d7823Smrg    inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
1744a96d7823Smrg
1745a96d7823Smrg    bfont->queryInfoSequence = conn->current_seq + 1;
1746a96d7823Smrg
1747a96d7823Smrg    _fs_add_req_log(conn, FS_QueryXInfo);
1748a96d7823Smrg    _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
1749a96d7823Smrg
1750a96d7823Smrg    if (!(bfont->flags & FontReopen))
1751a96d7823Smrg    {
1752a96d7823Smrg	extreq.reqType = FS_QueryXExtents16;
1753a96d7823Smrg	extreq.range = fsTrue;
1754a96d7823Smrg	extreq.fid = fsd->fontid;
1755a96d7823Smrg	extreq.num_ranges = 0;
1756a96d7823Smrg	extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
1757a96d7823Smrg
1758a96d7823Smrg	bfont->queryExtentsSequence = conn->current_seq + 1;
1759a96d7823Smrg
1760a96d7823Smrg	_fs_add_req_log(conn, FS_QueryXExtents16);
1761a96d7823Smrg	_fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
1762a96d7823Smrg    }
1763a96d7823Smrg
1764a96d7823Smrg#ifdef NCD
1765a96d7823Smrg    if (configData.ExtendedFontDiags)
1766a96d7823Smrg    {
1767a96d7823Smrg	memcpy(buf, name, MIN(256, namelen));
1768a96d7823Smrg	buf[MIN(256, namelen)] = '\0';
1769a96d7823Smrg	printf("Requesting font \"%s\" from font server \"%s\"\n",
1770a96d7823Smrg	       buf, font->fpe->name);
1771a96d7823Smrg    }
1772a96d7823Smrg#endif
1773a96d7823Smrg    _fs_prepare_for_reply (conn);
1774a96d7823Smrg
1775a96d7823Smrg    err = blockrec->errcode;
1776a96d7823Smrg    if (bfont->flags & FontOpenSync)
1777a96d7823Smrg    {
1778a96d7823Smrg	while (blockrec->errcode == StillWorking)
1779a96d7823Smrg	{
1780a96d7823Smrg	    if (fs_await_reply (conn) != FSIO_READY)
1781a96d7823Smrg	    {
1782a96d7823Smrg		blockrec->errcode = BadFontName;
1783a96d7823Smrg		break;
1784a96d7823Smrg	    }
1785a96d7823Smrg	    fs_read_reply (font->fpe, client);
1786a96d7823Smrg	}
1787a96d7823Smrg	err = blockrec->errcode;
1788a96d7823Smrg	if (err == Successful)
1789a96d7823Smrg	    *ppfont = bfont->pfont;
1790a96d7823Smrg	else
1791a96d7823Smrg	    fs_cleanup_bfont (bfont);
1792a96d7823Smrg	bfont->freeFont = FALSE;
1793a96d7823Smrg	_fs_remove_block_rec (conn, blockrec);
1794a96d7823Smrg    }
1795a96d7823Smrg    return err == StillWorking ? Suspended : err;
1796a96d7823Smrg}
1797a96d7823Smrg
1798a96d7823Smrgstatic void
1799a96d7823Smrgfs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1800a96d7823Smrg{
1801a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
1802a96d7823Smrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1803a96d7823Smrg    fsQueryXBitmaps16Req    bitreq;
1804a96d7823Smrg
1805a96d7823Smrg    /* send the request */
1806a96d7823Smrg    bitreq.reqType = FS_QueryXBitmaps16;
1807a96d7823Smrg    bitreq.fid = bfont->fontid;
1808a96d7823Smrg    bitreq.format = bfont->format;
1809a96d7823Smrg    bitreq.range = TRUE;
1810a96d7823Smrg    bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
1811a96d7823Smrg    bitreq.num_ranges = 0;
1812a96d7823Smrg
1813a96d7823Smrg    bfont->queryBitmapsSequence = conn->current_seq + 1;
1814a96d7823Smrg
1815a96d7823Smrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
1816a96d7823Smrg    _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
1817a96d7823Smrg}
1818a96d7823Smrg
1819a96d7823Smrg/* ARGSUSED */
1820a96d7823Smrgstatic int
1821a96d7823Smrgfs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1822a96d7823Smrg	     const char *name, int namelen,
1823a96d7823Smrg	     fsBitmapFormat format, fsBitmapFormatMask fmask,
1824a96d7823Smrg	     XID id, FontPtr *ppfont,
1825a96d7823Smrg	     char **alias, FontPtr non_cachable_font)
1826a96d7823Smrg{
1827a96d7823Smrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
1828a96d7823Smrg    FSBlockDataPtr	blockrec;
1829a96d7823Smrg    FSBlockedFontPtr	bfont;
1830a96d7823Smrg    int			err;
1831a96d7823Smrg
1832a96d7823Smrg    /* libfont interface expects ImageRectMin glyphs */
1833a96d7823Smrg    format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
1834a96d7823Smrg
1835a96d7823Smrg    *alias = (char *) 0;
1836a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1837a96d7823Smrg    {
1838a96d7823Smrg	if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
1839a96d7823Smrg	{
1840a96d7823Smrg	    err = blockrec->errcode;
1841a96d7823Smrg	    if (err == StillWorking)
1842a96d7823Smrg		return Suspended;
1843a96d7823Smrg
1844a96d7823Smrg	    bfont = (FSBlockedFontPtr) blockrec->data;
1845a96d7823Smrg	    if (err == Successful)
1846a96d7823Smrg		*ppfont = bfont->pfont;
1847a96d7823Smrg	    else
1848a96d7823Smrg		fs_cleanup_bfont (bfont);
1849a96d7823Smrg	    _fs_remove_block_rec (conn, blockrec);
1850a96d7823Smrg	    return err;
1851a96d7823Smrg	}
1852a96d7823Smrg    }
1853a96d7823Smrg    return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
1854a96d7823Smrg			     id, ppfont);
1855a96d7823Smrg}
1856a96d7823Smrg
1857a96d7823Smrg/* ARGSUSED */
1858a96d7823Smrgstatic int
1859a96d7823Smrgfs_send_close_font(FontPathElementPtr fpe, Font id)
1860a96d7823Smrg{
1861a96d7823Smrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
1862a96d7823Smrg    fsCloseReq  req;
1863a96d7823Smrg
1864a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
1865a96d7823Smrg	return Successful;
1866a96d7823Smrg    /* tell the font server to close the font */
1867a96d7823Smrg    req.reqType = FS_CloseFont;
1868a96d7823Smrg    req.pad = 0;
1869a96d7823Smrg    req.length = SIZEOF(fsCloseReq) >> 2;
1870a96d7823Smrg    req.id = id;
1871a96d7823Smrg    _fs_add_req_log(conn, FS_CloseFont);
1872a96d7823Smrg    _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
1873a96d7823Smrg
1874a96d7823Smrg    return Successful;
1875a96d7823Smrg}
1876a96d7823Smrg
1877a96d7823Smrg/* ARGSUSED */
1878a96d7823Smrgstatic void
1879a96d7823Smrgfs_close_font(FontPathElementPtr fpe, FontPtr pfont)
1880a96d7823Smrg{
1881a96d7823Smrg    FSFontDataPtr   fsd = (FSFontDataPtr) pfont->fpePrivate;
1882a96d7823Smrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
1883a96d7823Smrg
1884a96d7823Smrg    if (conn->generation == fsd->generation)
1885a96d7823Smrg	fs_send_close_font(fpe, fsd->fontid);
1886a96d7823Smrg
1887a96d7823Smrg#ifdef DEBUG
1888a96d7823Smrg    {
1889a96d7823Smrg	FSBlockDataPtr	    blockrec;
1890a96d7823Smrg	FSBlockedFontPtr    bfont;
1891a96d7823Smrg
1892a96d7823Smrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1893a96d7823Smrg	{
1894a96d7823Smrg	    if (blockrec->type == FS_OPEN_FONT)
1895a96d7823Smrg	    {
1896a96d7823Smrg		bfont = (FSBlockedFontPtr) blockrec->data;
1897a96d7823Smrg		if (bfont->pfont == pfont)
1898a96d7823Smrg		    fprintf (stderr, "closing font which hasn't been opened\n");
1899a96d7823Smrg	    }
1900a96d7823Smrg	}
1901a96d7823Smrg    }
1902a96d7823Smrg#endif
1903a96d7823Smrg    (*pfont->unload_font) (pfont);
1904a96d7823Smrg}
1905a96d7823Smrg
1906a96d7823Smrgstatic int
1907a96d7823Smrgfs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1908a96d7823Smrg{
1909a96d7823Smrg    FSBlockedGlyphPtr	    bglyph = (FSBlockedGlyphPtr) blockrec->data;
1910a96d7823Smrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
1911a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
1912a96d7823Smrg    FontPtr		    pfont = bglyph->pfont;
1913a96d7823Smrg					/* works for either blocked font
1914a96d7823Smrg					   or glyph rec...  pfont is at
1915a96d7823Smrg					   the very beginning of both
1916a96d7823Smrg					   blockrec->data structures */
1917a96d7823Smrg    FSFontDataPtr	    fsd = (FSFontDataPtr) (pfont->fpePrivate);
1918a96d7823Smrg    FSFontPtr		    fsdata = (FSFontPtr) pfont->fontPrivate;
1919a96d7823Smrg    FontInfoPtr		    pfi = &pfont->info;
1920a96d7823Smrg    fsQueryXBitmaps16Reply  *rep;
1921a96d7823Smrg    char		    *buf;
1922a96d7823Smrg    long		    bufleft; /* length of reply left to use */
1923a96d7823Smrg    fsOffset32		    *ppbits;
1924a96d7823Smrg    fsOffset32		    local_off;
1925a96d7823Smrg    char		    *off_adr;
1926a96d7823Smrg    pointer		    pbitmaps;
1927a96d7823Smrg    char		    *bits, *allbits;
1928a96d7823Smrg#ifdef DEBUG
1929a96d7823Smrg    char		    *origallbits;
1930a96d7823Smrg#endif
1931a96d7823Smrg    int			    i,
1932a96d7823Smrg			    err;
1933a96d7823Smrg    int			    nranges = 0;
1934a96d7823Smrg    int			    ret;
1935a96d7823Smrg    fsRange		    *nextrange = 0;
1936a96d7823Smrg    unsigned long	    minchar, maxchar;
1937a96d7823Smrg
1938a96d7823Smrg    rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
1939a96d7823Smrg    if (!rep || rep->type == FS_Error ||
1940a96d7823Smrg	(rep->length < LENGTHOF(fsQueryXBitmaps16Reply)))
1941a96d7823Smrg    {
1942a96d7823Smrg	if (ret == FSIO_BLOCK)
1943a96d7823Smrg	    return StillWorking;
1944a96d7823Smrg	if (rep)
1945a96d7823Smrg	    _fs_done_read (conn, rep->length << 2);
1946a96d7823Smrg	err = AllocError;
1947a96d7823Smrg	_fs_reply_failed (rep, fsQueryXBitmaps16Reply, "<");
1948a96d7823Smrg	goto bail;
1949a96d7823Smrg    }
1950a96d7823Smrg
1951a96d7823Smrg    buf = (char *) rep;
1952a96d7823Smrg    buf += SIZEOF (fsQueryXBitmaps16Reply);
1953a96d7823Smrg
1954a96d7823Smrg    bufleft = rep->length << 2;
1955a96d7823Smrg    bufleft -= SIZEOF (fsQueryXBitmaps16Reply);
1956a96d7823Smrg
1957a96d7823Smrg    if ((bufleft / SIZEOF (fsOffset32)) < rep->num_chars)
1958a96d7823Smrg    {
1959a96d7823Smrg#ifdef DEBUG
1960a96d7823Smrg	fprintf(stderr,
1961c7b4381aSmrg		"fsQueryXBitmaps16: num_chars (%u) > bufleft (%ld) / %d\n",
1962c7b4381aSmrg		(unsigned) rep->num_chars, bufleft, SIZEOF (fsOffset32));
1963a96d7823Smrg#endif
1964a96d7823Smrg	err = AllocError;
1965a96d7823Smrg	goto bail;
1966a96d7823Smrg    }
1967a96d7823Smrg    ppbits = (fsOffset32 *) buf;
1968a96d7823Smrg    buf += SIZEOF (fsOffset32) * (rep->num_chars);
1969a96d7823Smrg    bufleft -= SIZEOF (fsOffset32) * (rep->num_chars);
1970a96d7823Smrg
1971a96d7823Smrg    if (bufleft < rep->nbytes)
1972a96d7823Smrg    {
1973a96d7823Smrg#ifdef DEBUG
1974a96d7823Smrg	fprintf(stderr,
1975c7b4381aSmrg		"fsQueryXBitmaps16: nbytes (%u) > bufleft (%ld)\n",
1976c7b4381aSmrg		(unsigned) rep->nbytes, bufleft);
1977a96d7823Smrg#endif
1978a96d7823Smrg	err = AllocError;
1979a96d7823Smrg	goto bail;
1980a96d7823Smrg    }
1981a96d7823Smrg    pbitmaps = (pointer ) buf;
1982a96d7823Smrg
1983a96d7823Smrg    if (blockrec->type == FS_LOAD_GLYPHS)
1984a96d7823Smrg    {
1985a96d7823Smrg	nranges = bglyph->num_expected_ranges;
1986a96d7823Smrg	nextrange = bglyph->expected_ranges;
1987a96d7823Smrg    }
1988a96d7823Smrg
1989a96d7823Smrg    /* place the incoming glyphs */
1990a96d7823Smrg    if (nranges)
1991a96d7823Smrg    {
1992a96d7823Smrg	/* We're operating under the assumption that the ranges
1993a96d7823Smrg	   requested in the LoadGlyphs call were all legal for this
1994a96d7823Smrg	   font, and that individual ranges do not cover multiple
1995a96d7823Smrg	   rows...  fs_build_range() is designed to ensure this. */
1996a96d7823Smrg	minchar = (nextrange->min_char_high - pfi->firstRow) *
1997a96d7823Smrg		  (pfi->lastCol - pfi->firstCol + 1) +
1998a96d7823Smrg		  nextrange->min_char_low - pfi->firstCol;
1999a96d7823Smrg	maxchar = (nextrange->max_char_high - pfi->firstRow) *
2000a96d7823Smrg		  (pfi->lastCol - pfi->firstCol + 1) +
2001a96d7823Smrg		  nextrange->max_char_low - pfi->firstCol;
2002a96d7823Smrg	nextrange++;
2003a96d7823Smrg    }
2004a96d7823Smrg    else
2005a96d7823Smrg    {
2006a96d7823Smrg	minchar = 0;
2007a96d7823Smrg	maxchar = rep->num_chars;
2008a96d7823Smrg    }
2009a96d7823Smrg
2010a96d7823Smrg    off_adr = (char *)ppbits;
2011a96d7823Smrg
2012a96d7823Smrg    allbits = fs_alloc_glyphs (pfont, rep->nbytes);
2013a96d7823Smrg
2014a96d7823Smrg    if (!allbits)
2015a96d7823Smrg    {
2016a96d7823Smrg	err = AllocError;
2017a96d7823Smrg	goto bail;
2018a96d7823Smrg    }
2019a96d7823Smrg
2020a96d7823Smrg#ifdef DEBUG
2021a96d7823Smrg    origallbits = allbits;
2022a96d7823Smrg    fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
2023a96d7823Smrg	     (int) rep->num_chars, (int) rep->nbytes, fsd->name);
2024a96d7823Smrg#endif
2025a96d7823Smrg
2026a96d7823Smrg    for (i = 0; i < rep->num_chars; i++)
2027a96d7823Smrg    {
2028a96d7823Smrg	memcpy(&local_off, off_adr, SIZEOF(fsOffset32));	/* align it */
2029a96d7823Smrg	if (blockrec->type == FS_OPEN_FONT ||
2030a96d7823Smrg	    fsdata->encoding[minchar].bits == &_fs_glyph_requested)
2031a96d7823Smrg	{
2032a96d7823Smrg	    /*
2033a96d7823Smrg	     * Broken X font server returns bits for missing characters
2034a96d7823Smrg	     * when font is padded
2035a96d7823Smrg	     */
2036a96d7823Smrg	    if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
2037a96d7823Smrg	    {
2038a96d7823Smrg		if (local_off.length &&
2039a96d7823Smrg		    (local_off.position < rep->nbytes) &&
2040a96d7823Smrg		    (local_off.length <= (rep->nbytes - local_off.position)))
2041a96d7823Smrg		{
2042a96d7823Smrg		    bits = allbits;
2043a96d7823Smrg		    allbits += local_off.length;
2044a96d7823Smrg		    memcpy(bits, (char *)pbitmaps + local_off.position,
2045a96d7823Smrg			   local_off.length);
2046a96d7823Smrg		}
2047a96d7823Smrg		else
2048a96d7823Smrg		    bits = &_fs_glyph_zero_length;
2049a96d7823Smrg	    }
2050a96d7823Smrg	    else
2051a96d7823Smrg		bits = 0;
2052a96d7823Smrg	    if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
2053a96d7823Smrg		fsd->glyphs_to_get--;
2054a96d7823Smrg	    fsdata->encoding[minchar].bits = bits;
2055a96d7823Smrg	}
2056a96d7823Smrg	if (minchar++ == maxchar)
2057a96d7823Smrg	{
2058a96d7823Smrg	    if (!--nranges) break;
2059a96d7823Smrg	    minchar = (nextrange->min_char_high - pfi->firstRow) *
2060a96d7823Smrg		      (pfi->lastCol - pfi->firstCol + 1) +
2061a96d7823Smrg		      nextrange->min_char_low - pfi->firstCol;
2062a96d7823Smrg	    maxchar = (nextrange->max_char_high - pfi->firstRow) *
2063a96d7823Smrg		      (pfi->lastCol - pfi->firstCol + 1) +
2064a96d7823Smrg		      nextrange->max_char_low - pfi->firstCol;
2065a96d7823Smrg	    nextrange++;
2066a96d7823Smrg	}
2067a96d7823Smrg	off_adr += SIZEOF(fsOffset32);
2068a96d7823Smrg    }
2069a96d7823Smrg#ifdef DEBUG
2070a96d7823Smrg    fprintf (stderr, "Used %d bytes instead of %d\n",
2071a96d7823Smrg	     (int) (allbits - origallbits), (int) rep->nbytes);
2072a96d7823Smrg#endif
2073a96d7823Smrg
2074a96d7823Smrg    if (blockrec->type == FS_OPEN_FONT)
2075a96d7823Smrg    {
2076a96d7823Smrg	fsd->glyphs_to_get = 0;
2077a96d7823Smrg	bfont->state = FS_DONE_REPLY;
2078a96d7823Smrg    }
2079a96d7823Smrg    err = Successful;
2080a96d7823Smrg
2081a96d7823Smrgbail:
2082c7b4381aSmrg    if (rep)
2083c7b4381aSmrg	_fs_done_read (conn, rep->length << 2);
2084a96d7823Smrg    return err;
2085a96d7823Smrg}
2086a96d7823Smrg
2087a96d7823Smrgstatic int
2088a96d7823Smrgfs_send_load_glyphs(pointer client, FontPtr pfont,
2089a96d7823Smrg		    int nranges, fsRange *ranges)
2090a96d7823Smrg{
2091a96d7823Smrg    FontPathElementPtr	    fpe = pfont->fpe;
2092a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
2093a96d7823Smrg    FSBlockedGlyphPtr	    blockedglyph;
2094a96d7823Smrg    fsQueryXBitmaps16Req    req;
2095a96d7823Smrg    FSBlockDataPtr	    blockrec;
2096a96d7823Smrg
2097a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
2098a96d7823Smrg	return BadCharRange;
2099a96d7823Smrg
2100a96d7823Smrg    /* make a new block record, and add it to the end of the list */
2101a96d7823Smrg    blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
2102a96d7823Smrg    if (!blockrec)
2103a96d7823Smrg	return AllocError;
2104a96d7823Smrg    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2105a96d7823Smrg    blockedglyph->pfont = pfont;
2106a96d7823Smrg    blockedglyph->num_expected_ranges = nranges;
2107a96d7823Smrg    /* Assumption: it's our job to free ranges */
2108a96d7823Smrg    blockedglyph->expected_ranges = ranges;
2109a96d7823Smrg    blockedglyph->clients_depending = (FSClientsDependingPtr)0;
2110a96d7823Smrg
2111a96d7823Smrg    if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
2112a96d7823Smrg    {
2113a96d7823Smrg	_fs_pending_reply (conn);
2114a96d7823Smrg	return Suspended;
2115a96d7823Smrg    }
2116a96d7823Smrg
2117a96d7823Smrg    /* send the request */
2118a96d7823Smrg    req.reqType = FS_QueryXBitmaps16;
2119a96d7823Smrg    req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
2120a96d7823Smrg    req.format = pfont->format;
2121a96d7823Smrg    if (pfont->info.terminalFont)
2122a96d7823Smrg	req.format = (req.format & ~(BitmapFormatImageRectMask)) |
2123a96d7823Smrg		     BitmapFormatImageRectMax;
2124a96d7823Smrg    req.range = TRUE;
2125a96d7823Smrg    /* each range takes up 4 bytes */
2126a96d7823Smrg    req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
2127a96d7823Smrg    req.num_ranges = nranges * 2;	/* protocol wants count of fsChar2bs */
2128a96d7823Smrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
2129a96d7823Smrg    _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
2130a96d7823Smrg
2131a96d7823Smrg    blockrec->sequenceNumber = conn->current_seq;
2132a96d7823Smrg
2133a96d7823Smrg    /* Send ranges to the server... pack into a char array by hand
2134a96d7823Smrg       to avoid structure-packing portability problems and to
2135a96d7823Smrg       handle swapping for version1 protocol */
2136a96d7823Smrg    if (nranges)
2137a96d7823Smrg    {
2138a96d7823Smrg#define RANGE_BUFFER_SIZE 64
2139a96d7823Smrg#define RANGE_BUFFER_SIZE_MASK 63
2140a96d7823Smrg	int i;
2141a96d7823Smrg	char range_buffer[RANGE_BUFFER_SIZE * 4];
2142a96d7823Smrg	char *range_buffer_p;
2143a96d7823Smrg
2144a96d7823Smrg	range_buffer_p = range_buffer;
2145a96d7823Smrg	for (i = 0; i < nranges;)
2146a96d7823Smrg	{
2147a96d7823Smrg	    if (conn->fsMajorVersion > 1)
2148a96d7823Smrg	    {
2149a96d7823Smrg		*range_buffer_p++ = ranges[i].min_char_high;
2150a96d7823Smrg		*range_buffer_p++ = ranges[i].min_char_low;
2151a96d7823Smrg		*range_buffer_p++ = ranges[i].max_char_high;
2152a96d7823Smrg		*range_buffer_p++ = ranges[i].max_char_low;
2153a96d7823Smrg	    }
2154a96d7823Smrg	    else
2155a96d7823Smrg	    {
2156a96d7823Smrg		*range_buffer_p++ = ranges[i].min_char_low;
2157a96d7823Smrg		*range_buffer_p++ = ranges[i].min_char_high;
2158a96d7823Smrg		*range_buffer_p++ = ranges[i].max_char_low;
2159a96d7823Smrg		*range_buffer_p++ = ranges[i].max_char_high;
2160a96d7823Smrg	    }
2161a96d7823Smrg
2162a96d7823Smrg	    if (!(++i & RANGE_BUFFER_SIZE_MASK))
2163a96d7823Smrg	    {
2164a96d7823Smrg		_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
2165a96d7823Smrg		range_buffer_p = range_buffer;
2166a96d7823Smrg	    }
2167a96d7823Smrg	}
2168a96d7823Smrg	if (i &= RANGE_BUFFER_SIZE_MASK)
2169a96d7823Smrg	    _fs_write(conn, range_buffer, i * 4);
2170a96d7823Smrg    }
2171a96d7823Smrg
2172a96d7823Smrg    _fs_prepare_for_reply (conn);
2173a96d7823Smrg    return Suspended;
2174a96d7823Smrg}
2175a96d7823Smrg
2176a96d7823Smrgstatic int
2177a96d7823Smrg_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
2178a96d7823Smrg		unsigned int nchars, int item_size, unsigned char *data)
2179a96d7823Smrg{
2180a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) pfont->fpe->private;
2181a96d7823Smrg    int			    nranges = 0;
2182a96d7823Smrg    fsRange		    *ranges = NULL;
2183a96d7823Smrg    int			    res;
2184a96d7823Smrg    FSBlockDataPtr	    blockrec;
2185a96d7823Smrg    FSBlockedGlyphPtr	    blockedglyph;
2186a96d7823Smrg    FSClientsDependingPtr   *clients_depending = NULL;
2187a96d7823Smrg    int			    err;
2188a96d7823Smrg
2189a96d7823Smrg    /* see if the result is already there */
2190a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2191a96d7823Smrg    {
2192a96d7823Smrg	if (blockrec->type == FS_LOAD_GLYPHS)
2193a96d7823Smrg	{
2194a96d7823Smrg	    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2195a96d7823Smrg	    if (blockedglyph->pfont == pfont)
2196a96d7823Smrg	    {
2197a96d7823Smrg		/* Look for this request */
2198a96d7823Smrg		if (blockrec->client == client)
2199a96d7823Smrg		{
2200a96d7823Smrg		    err = blockrec->errcode;
2201a96d7823Smrg		    if (err == StillWorking)
2202a96d7823Smrg			return Suspended;
2203a96d7823Smrg		    _fs_signal_clients_depending(&blockedglyph->clients_depending);
2204a96d7823Smrg		    _fs_remove_block_rec(conn, blockrec);
2205a96d7823Smrg		    return err;
2206a96d7823Smrg		}
2207a96d7823Smrg		/* We've found an existing LoadGlyphs blockrec for this
2208a96d7823Smrg		   font but for another client.  Rather than build a
2209a96d7823Smrg		   blockrec for it now (which entails some complex
2210a96d7823Smrg		   maintenance), we'll add it to a queue of clients to
2211a96d7823Smrg		   be signalled when the existing LoadGlyphs is
2212a96d7823Smrg		   completed.  */
2213a96d7823Smrg		clients_depending = &blockedglyph->clients_depending;
2214a96d7823Smrg		break;
2215a96d7823Smrg	    }
2216a96d7823Smrg	}
2217a96d7823Smrg	else if (blockrec->type == FS_OPEN_FONT)
2218a96d7823Smrg	{
2219a96d7823Smrg	    FSBlockedFontPtr bfont;
2220a96d7823Smrg	    bfont = (FSBlockedFontPtr) blockrec->data;
2221a96d7823Smrg	    if (bfont->pfont == pfont)
2222a96d7823Smrg	    {
2223a96d7823Smrg		/*
2224a96d7823Smrg		 * An OpenFont is pending for this font, this must
2225a96d7823Smrg		 * be from a reopen attempt, so finish the open
2226a96d7823Smrg		 * attempt and retry the LoadGlyphs
2227a96d7823Smrg		 */
2228a96d7823Smrg		if (blockrec->client == client)
2229a96d7823Smrg		{
2230a96d7823Smrg		    err = blockrec->errcode;
2231a96d7823Smrg		    if (err == StillWorking)
2232a96d7823Smrg			return Suspended;
2233a96d7823Smrg
2234a96d7823Smrg		    _fs_signal_clients_depending(&bfont->clients_depending);
2235a96d7823Smrg		    _fs_remove_block_rec(conn, blockrec);
2236a96d7823Smrg		    if (err != Successful)
2237a96d7823Smrg			return err;
2238a96d7823Smrg		    break;
2239a96d7823Smrg		}
2240a96d7823Smrg		/* We've found an existing OpenFont blockrec for this
2241a96d7823Smrg		   font but for another client.  Rather than build a
2242a96d7823Smrg		   blockrec for it now (which entails some complex
2243a96d7823Smrg		   maintenance), we'll add it to a queue of clients to
2244a96d7823Smrg		   be signalled when the existing OpenFont is
2245a96d7823Smrg		   completed.  */
2246a96d7823Smrg		if (blockrec->errcode == StillWorking)
2247a96d7823Smrg		{
2248a96d7823Smrg		    clients_depending = &bfont->clients_depending;
2249a96d7823Smrg		    break;
2250a96d7823Smrg		}
2251a96d7823Smrg	    }
2252a96d7823Smrg	}
2253a96d7823Smrg    }
2254a96d7823Smrg
2255a96d7823Smrg    /*
2256a96d7823Smrg     * see if the desired glyphs already exist, and return Successful if they
2257a96d7823Smrg     * do, otherwise build up character range/character string
2258a96d7823Smrg     */
2259a96d7823Smrg    res = fs_build_range(pfont, range_flag, nchars, item_size, data,
2260a96d7823Smrg			 &nranges, &ranges);
2261a96d7823Smrg
2262a96d7823Smrg    switch (res)
2263a96d7823Smrg    {
2264a96d7823Smrg	case AccessDone:
2265a96d7823Smrg	    return Successful;
2266a96d7823Smrg
2267a96d7823Smrg	case Successful:
2268a96d7823Smrg	    break;
2269a96d7823Smrg
2270a96d7823Smrg	default:
2271a96d7823Smrg	    return res;
2272a96d7823Smrg    }
2273a96d7823Smrg
2274a96d7823Smrg    /*
2275a96d7823Smrg     * If clients_depending is not null, this request must wait for
2276a96d7823Smrg     * some prior request(s) to complete.
2277a96d7823Smrg     */
2278a96d7823Smrg    if (clients_depending)
2279a96d7823Smrg    {
2280a96d7823Smrg	/* Since we're not ready to send the load_glyphs request yet,
2281a96d7823Smrg	   clean up the damage (if any) caused by the fs_build_range()
2282a96d7823Smrg	   call. */
2283a96d7823Smrg	if (nranges)
2284a96d7823Smrg	{
2285a96d7823Smrg	    _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2286a96d7823Smrg	    free(ranges);
2287a96d7823Smrg	}
2288a96d7823Smrg	return _fs_add_clients_depending(clients_depending, client);
2289a96d7823Smrg    }
2290a96d7823Smrg
2291a96d7823Smrg    /*
2292a96d7823Smrg     * If fsd->generation != conn->generation, the font has been closed
2293a96d7823Smrg     * due to a lost connection.  We will reopen it, which will result
2294a96d7823Smrg     * in one of three things happening:
2295a96d7823Smrg     *	 1) The open will succeed and obtain the same font.  Life
2296a96d7823Smrg     *	    is wonderful.
2297a96d7823Smrg     *	 2) The open will fail.  There is code above to recognize this
2298a96d7823Smrg     *	    and flunk the LoadGlyphs request.  The client might not be
2299a96d7823Smrg     *	    thrilled.
2300a96d7823Smrg     *	 3) Worst case: the open will succeed but the font we open will
2301a96d7823Smrg     *	    be different.  The fs_read_query_info() procedure attempts
2302a96d7823Smrg     *	    to detect this by comparing the existing metrics and
2303a96d7823Smrg     *	    properties against those of the reopened font... if they
2304a96d7823Smrg     *	    don't match, we flunk the reopen, which eventually results
2305a96d7823Smrg     *	    in flunking the LoadGlyphs request.  We could go a step
2306a96d7823Smrg     *	    further and compare the extents, but this should be
2307a96d7823Smrg     *	    sufficient.
2308a96d7823Smrg     */
2309a96d7823Smrg    if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
2310a96d7823Smrg    {
2311a96d7823Smrg	/* Since we're not ready to send the load_glyphs request yet,
2312a96d7823Smrg	   clean up the damage caused by the fs_build_range() call. */
2313a96d7823Smrg	_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2314a96d7823Smrg	free(ranges);
2315a96d7823Smrg
2316a96d7823Smrg	/* Now try to reopen the font. */
2317a96d7823Smrg	return fs_send_open_font(client, pfont->fpe,
2318a96d7823Smrg				 (Mask)FontReopen, (char *)0, 0,
2319a96d7823Smrg				 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
2320a96d7823Smrg				 (XID)0, &pfont);
2321a96d7823Smrg    }
2322a96d7823Smrg
2323a96d7823Smrg    return fs_send_load_glyphs(client, pfont, nranges, ranges);
2324a96d7823Smrg}
2325a96d7823Smrg
2326a96d7823Smrgint
2327a96d7823Smrgfs_load_all_glyphs(FontPtr pfont)
2328a96d7823Smrg{
2329a96d7823Smrg    int		err;
2330a96d7823Smrg    FSFpePtr	conn = (FSFpePtr) pfont->fpe->private;
2331a96d7823Smrg
2332a96d7823Smrg    /*
2333a96d7823Smrg     * The purpose of this procedure is to load all glyphs in the event
2334a96d7823Smrg     * that we're dealing with someone who doesn't understand the finer
2335a96d7823Smrg     * points of glyph caching...  it is called from _fs_get_glyphs() if
2336a96d7823Smrg     * the latter is called to get glyphs that have not yet been loaded.
2337a96d7823Smrg     * We assume that the caller will not know how to handle a return
2338a96d7823Smrg     * value of Suspended (usually the case for a GetGlyphs() caller),
2339a96d7823Smrg     * so this procedure hangs around, freezing the server, for the
2340a96d7823Smrg     * request to complete.  This is an unpleasant kluge called to
2341a96d7823Smrg     * perform an unpleasant job that, we hope, will never be required.
2342a96d7823Smrg     */
2343a96d7823Smrg
2344a96d7823Smrg    while ((err = _fs_load_glyphs(__GetServerClient(), pfont, TRUE, 0, 0, NULL)) ==
2345a96d7823Smrg	   Suspended)
2346a96d7823Smrg    {
2347a96d7823Smrg	if (fs_await_reply (conn) != FSIO_READY)
2348a96d7823Smrg	{
2349a96d7823Smrg	    /* Get rid of blockrec */
2350a96d7823Smrg	    fs_client_died(__GetServerClient(), pfont->fpe);
2351a96d7823Smrg	    err = BadCharRange;
2352a96d7823Smrg	    break;
2353a96d7823Smrg	}
2354a96d7823Smrg	fs_read_reply (pfont->fpe, __GetServerClient());
2355a96d7823Smrg    }
2356a96d7823Smrg    return err;
2357a96d7823Smrg}
2358a96d7823Smrg
2359a96d7823Smrgstatic int
2360a96d7823Smrgfs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2361a96d7823Smrg{
2362a96d7823Smrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
2363a96d7823Smrg    FSBlockedListPtr	blist = (FSBlockedListPtr) blockrec->data;
2364a96d7823Smrg    fsListFontsReply	*rep;
2365a96d7823Smrg    char		*data;
2366a96d7823Smrg    long		dataleft; /* length of reply left to use */
2367a96d7823Smrg    int			length,
2368a96d7823Smrg			i,
2369a96d7823Smrg			ret;
2370a96d7823Smrg    int			err;
2371a96d7823Smrg
2372a96d7823Smrg    rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
2373a96d7823Smrg    if (!rep || rep->type == FS_Error ||
2374a96d7823Smrg	(rep->length < LENGTHOF(fsListFontsReply)))
2375a96d7823Smrg    {
2376a96d7823Smrg	if (ret == FSIO_BLOCK)
2377a96d7823Smrg	    return StillWorking;
2378a96d7823Smrg	if (rep)
2379a96d7823Smrg	    _fs_done_read (conn, rep->length << 2);
2380a96d7823Smrg	_fs_reply_failed (rep, fsListFontsReply, "<");
2381a96d7823Smrg	return AllocError;
2382a96d7823Smrg    }
2383a96d7823Smrg    data = (char *) rep + SIZEOF (fsListFontsReply);
2384a96d7823Smrg    dataleft = (rep->length << 2) - SIZEOF (fsListFontsReply);
2385a96d7823Smrg
2386a96d7823Smrg    err = Successful;
2387a96d7823Smrg    /* copy data into FontPathRecord */
2388a96d7823Smrg    for (i = 0; i < rep->nFonts; i++)
2389a96d7823Smrg    {
2390a96d7823Smrg	if (dataleft < 1)
2391a96d7823Smrg	    break;
2392a96d7823Smrg	length = *(unsigned char *)data++;
2393a96d7823Smrg	dataleft--; /* used length byte */
2394a96d7823Smrg	if (length > dataleft) {
2395a96d7823Smrg#ifdef DEBUG
2396a96d7823Smrg	    fprintf(stderr,
2397a96d7823Smrg		    "fsListFonts: name length (%d) > dataleft (%ld)\n",
2398a96d7823Smrg		    length, dataleft);
2399a96d7823Smrg#endif
2400a96d7823Smrg	    err = BadFontName;
2401a96d7823Smrg	    break;
2402a96d7823Smrg	}
2403a96d7823Smrg	err = xfont2_add_font_names_name(blist->names, data, length);
2404a96d7823Smrg	if (err != Successful)
2405a96d7823Smrg	    break;
2406a96d7823Smrg	data += length;
2407a96d7823Smrg	dataleft -= length;
2408a96d7823Smrg    }
2409a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
2410a96d7823Smrg    return err;
2411a96d7823Smrg}
2412a96d7823Smrg
2413a96d7823Smrgstatic int
2414a96d7823Smrgfs_send_list_fonts(pointer client, FontPathElementPtr fpe, const char *pattern,
2415a96d7823Smrg		   int patlen, int maxnames, FontNamesPtr newnames)
2416a96d7823Smrg{
2417a96d7823Smrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
2418a96d7823Smrg    FSBlockDataPtr	blockrec;
2419a96d7823Smrg    FSBlockedListPtr	blockedlist;
2420a96d7823Smrg    fsListFontsReq	req;
2421a96d7823Smrg
2422a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
2423a96d7823Smrg	return BadFontName;
2424a96d7823Smrg
2425a96d7823Smrg    /* make a new block record, and add it to the end of the list */
2426a96d7823Smrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
2427a96d7823Smrg    if (!blockrec)
2428a96d7823Smrg	return AllocError;
2429a96d7823Smrg    blockedlist = (FSBlockedListPtr) blockrec->data;
2430a96d7823Smrg    blockedlist->names = newnames;
2431a96d7823Smrg
2432a96d7823Smrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2433a96d7823Smrg    {
2434a96d7823Smrg	_fs_pending_reply (conn);
2435a96d7823Smrg	return Suspended;
2436a96d7823Smrg    }
2437a96d7823Smrg
2438a96d7823Smrg    _fs_client_access (conn, client, FALSE);
2439a96d7823Smrg    _fs_client_resolution(conn);
2440a96d7823Smrg
2441a96d7823Smrg    /* send the request */
2442a96d7823Smrg    req.reqType = FS_ListFonts;
2443a96d7823Smrg    req.pad = 0;
2444a96d7823Smrg    req.maxNames = maxnames;
2445a96d7823Smrg    req.nbytes = patlen;
2446a96d7823Smrg    req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
2447a96d7823Smrg    _fs_add_req_log(conn, FS_ListFonts);
2448a96d7823Smrg    _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
2449a96d7823Smrg    _fs_write_pad(conn, (char *) pattern, patlen);
2450a96d7823Smrg
2451a96d7823Smrg    blockrec->sequenceNumber = conn->current_seq;
2452a96d7823Smrg
2453a96d7823Smrg#ifdef NCD
2454a96d7823Smrg    if (configData.ExtendedFontDiags) {
2455a96d7823Smrg	char        buf[256];
2456a96d7823Smrg
2457a96d7823Smrg	memcpy(buf, pattern, MIN(256, patlen));
2458a96d7823Smrg	buf[MIN(256, patlen)] = '\0';
2459a96d7823Smrg	printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
2460a96d7823Smrg	       buf, fpe->name);
2461a96d7823Smrg    }
2462a96d7823Smrg#endif
2463a96d7823Smrg
2464a96d7823Smrg    _fs_prepare_for_reply (conn);
2465a96d7823Smrg    return Suspended;
2466a96d7823Smrg}
2467a96d7823Smrg
2468a96d7823Smrgstatic int
2469a96d7823Smrgfs_list_fonts(pointer client, FontPathElementPtr fpe,
2470a96d7823Smrg	      const char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
2471a96d7823Smrg{
2472a96d7823Smrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
2473a96d7823Smrg    FSBlockDataPtr	blockrec;
2474a96d7823Smrg    int			err;
2475a96d7823Smrg
2476a96d7823Smrg    /* see if the result is already there */
2477a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2478a96d7823Smrg    {
2479a96d7823Smrg	if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
2480a96d7823Smrg	{
2481a96d7823Smrg	    err = blockrec->errcode;
2482a96d7823Smrg	    if (err == StillWorking)
2483a96d7823Smrg		return Suspended;
2484a96d7823Smrg	    _fs_remove_block_rec(conn, blockrec);
2485a96d7823Smrg	    return err;
2486a96d7823Smrg	}
2487a96d7823Smrg    }
2488a96d7823Smrg
2489a96d7823Smrg    /* didn't find waiting record, so send a new one */
2490a96d7823Smrg    return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
2491a96d7823Smrg}
2492a96d7823Smrg
2493a96d7823Smrg/*
2494a96d7823Smrg * Read a single list info reply and restart for the next reply
2495a96d7823Smrg */
2496a96d7823Smrgstatic int
2497a96d7823Smrgfs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2498a96d7823Smrg{
2499a96d7823Smrg    FSBlockedListInfoPtr	binfo = (FSBlockedListInfoPtr) blockrec->data;
2500a96d7823Smrg    fsListFontsWithXInfoReply	*rep;
2501a96d7823Smrg    char			*buf;
2502a96d7823Smrg    long			bufleft;
2503a96d7823Smrg    FSFpePtr			conn = (FSFpePtr) fpe->private;
2504a96d7823Smrg    fsPropInfo			*pi;
2505a96d7823Smrg    fsPropOffset		*po;
2506a96d7823Smrg    pointer			pd;
2507a96d7823Smrg    int				ret;
2508a96d7823Smrg    int				err;
2509a96d7823Smrg
2510a96d7823Smrg    /* clean up anything from the last trip */
2511a96d7823Smrg    _fs_free_props (&binfo->info);
2512a96d7823Smrg
2513a96d7823Smrg    rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
2514a96d7823Smrg    if (!rep || rep->type == FS_Error ||
2515a96d7823Smrg	((rep->nameLength != 0) &&
2516a96d7823Smrg	 (rep->length < LENGTHOF(fsListFontsWithXInfoReply))))
2517a96d7823Smrg    {
2518a96d7823Smrg	if (ret == FSIO_BLOCK)
2519a96d7823Smrg	    return StillWorking;
2520a96d7823Smrg	binfo->status = FS_LFWI_FINISHED;
2521a96d7823Smrg	err = AllocError;
2522a96d7823Smrg	_fs_reply_failed (rep, fsListFontsWithXInfoReply, "<");
2523a96d7823Smrg	goto done;
2524a96d7823Smrg    }
2525a96d7823Smrg    /*
2526a96d7823Smrg     * Normal termination -- the list ends with a name of length 0
2527a96d7823Smrg     */
2528a96d7823Smrg    if (rep->nameLength == 0)
2529a96d7823Smrg    {
2530a96d7823Smrg#ifdef DEBUG
2531a96d7823Smrg	fprintf (stderr, "fs_read_list_info done\n");
2532a96d7823Smrg#endif
2533a96d7823Smrg	binfo->status = FS_LFWI_FINISHED;
2534a96d7823Smrg	err = BadFontName;
2535a96d7823Smrg	goto done;
2536a96d7823Smrg    }
2537a96d7823Smrg
2538a96d7823Smrg    buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
2539a96d7823Smrg    bufleft = (rep->length << 2) - SIZEOF (fsListFontsWithXInfoReply);
2540a96d7823Smrg
2541a96d7823Smrg    /*
2542a96d7823Smrg     * The original FS implementation didn't match
2543a96d7823Smrg     * the spec, version 1 was respecified to match the FS.
2544a96d7823Smrg     * Version 2 matches the original intent
2545a96d7823Smrg     */
2546a96d7823Smrg    if (conn->fsMajorVersion <= 1)
2547a96d7823Smrg    {
2548a96d7823Smrg	if (rep->nameLength > bufleft) {
2549a96d7823Smrg#ifdef DEBUG
2550a96d7823Smrg	    fprintf(stderr,
2551a96d7823Smrg		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
2552a96d7823Smrg		    (int) rep->nameLength, bufleft);
2553a96d7823Smrg#endif
2554a96d7823Smrg	    err = AllocError;
2555a96d7823Smrg	    goto done;
2556a96d7823Smrg	}
2557a96d7823Smrg	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
2558a96d7823Smrg	memcpy (binfo->name, buf, rep->nameLength);
2559a96d7823Smrg	buf += _fs_pad_length (rep->nameLength);
2560a96d7823Smrg	bufleft -= _fs_pad_length (rep->nameLength);
2561a96d7823Smrg    }
2562a96d7823Smrg    pi = (fsPropInfo *) buf;
2563a96d7823Smrg    if (SIZEOF (fsPropInfo) > bufleft) {
2564a96d7823Smrg#ifdef DEBUG
2565a96d7823Smrg	fprintf(stderr,
2566a96d7823Smrg		"fsListFontsWithXInfo: PropInfo length (%d) > bufleft (%ld)\n",
2567a96d7823Smrg		(int) SIZEOF (fsPropInfo), bufleft);
2568a96d7823Smrg#endif
2569a96d7823Smrg	err = AllocError;
2570a96d7823Smrg	goto done;
2571a96d7823Smrg    }
2572a96d7823Smrg    bufleft -= SIZEOF (fsPropInfo);
2573a96d7823Smrg    buf += SIZEOF (fsPropInfo);
2574a96d7823Smrg    po = (fsPropOffset *) buf;
2575a96d7823Smrg    if (pi->num_offsets > (bufleft / SIZEOF (fsPropOffset))) {
2576a96d7823Smrg#ifdef DEBUG
2577a96d7823Smrg	fprintf(stderr,
2578c7b4381aSmrg		"fsListFontsWithXInfo: offset length (%u * %d) > bufleft (%ld)\n",
2579c7b4381aSmrg		(unsigned) pi->num_offsets, (int) SIZEOF (fsPropOffset), bufleft);
2580a96d7823Smrg#endif
2581a96d7823Smrg	err = AllocError;
2582a96d7823Smrg	goto done;
2583a96d7823Smrg    }
2584a96d7823Smrg    bufleft -= pi->num_offsets * SIZEOF (fsPropOffset);
2585a96d7823Smrg    buf += pi->num_offsets * SIZEOF (fsPropOffset);
2586a96d7823Smrg    pd = (pointer) buf;
2587a96d7823Smrg    if (pi->data_len > bufleft) {
2588a96d7823Smrg#ifdef DEBUG
2589a96d7823Smrg	fprintf(stderr,
2590c7b4381aSmrg		"fsListFontsWithXInfo: data length (%u) > bufleft (%ld)\n",
2591c7b4381aSmrg		(unsigned) pi->data_len, bufleft);
2592a96d7823Smrg#endif
2593a96d7823Smrg	err = AllocError;
2594a96d7823Smrg	goto done;
2595a96d7823Smrg    }
2596a96d7823Smrg    bufleft -= pi->data_len;
2597a96d7823Smrg    buf += pi->data_len;
2598a96d7823Smrg    if (conn->fsMajorVersion > 1)
2599a96d7823Smrg    {
2600a96d7823Smrg	if (rep->nameLength > bufleft) {
2601a96d7823Smrg#ifdef DEBUG
2602a96d7823Smrg	    fprintf(stderr,
2603a96d7823Smrg		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
2604a96d7823Smrg		    (int) rep->nameLength, bufleft);
2605a96d7823Smrg#endif
2606a96d7823Smrg	    err = AllocError;
2607a96d7823Smrg	    goto done;
2608a96d7823Smrg	}
2609a96d7823Smrg	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
2610a96d7823Smrg	memcpy (binfo->name, buf, rep->nameLength);
2611a96d7823Smrg	buf += _fs_pad_length (rep->nameLength);
2612a96d7823Smrg	bufleft -= _fs_pad_length (rep->nameLength);
2613a96d7823Smrg    }
2614a96d7823Smrg
2615a96d7823Smrg#ifdef DEBUG
2616a96d7823Smrg    binfo->name[rep->nameLength] = '\0';
2617a96d7823Smrg    fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
2618a96d7823Smrg#endif
2619a96d7823Smrg    err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
2620a96d7823Smrg    if (err != Successful)
2621a96d7823Smrg    {
2622a96d7823Smrg	binfo->status = FS_LFWI_FINISHED;
2623a96d7823Smrg	goto done;
2624a96d7823Smrg    }
2625a96d7823Smrg    binfo->namelen = rep->nameLength;
2626a96d7823Smrg    binfo->remaining = rep->nReplies;
2627a96d7823Smrg
2628a96d7823Smrg    binfo->status = FS_LFWI_REPLY;
2629a96d7823Smrg
2630a96d7823Smrg    /* disable this font server until we've processed this response */
2631a96d7823Smrg    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
2632a96d7823Smrg    conn_stop_listening(conn);
2633a96d7823Smrgdone:
2634a96d7823Smrg    _fs_done_read (conn, rep->length << 2);
2635a96d7823Smrg    return err;
2636a96d7823Smrg}
2637a96d7823Smrg
2638a96d7823Smrg/* ARGSUSED */
2639a96d7823Smrgstatic int
2640a96d7823Smrgfs_start_list_with_info(pointer client, FontPathElementPtr fpe,
2641a96d7823Smrg			const char *pattern, int len, int maxnames, pointer *pdata)
2642a96d7823Smrg{
2643a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
2644a96d7823Smrg    FSBlockDataPtr	    blockrec;
2645a96d7823Smrg    FSBlockedListInfoPtr    binfo;
2646a96d7823Smrg    fsListFontsWithXInfoReq req;
2647a96d7823Smrg
2648a96d7823Smrg    if (conn->blockState & FS_GIVE_UP)
2649a96d7823Smrg	return BadFontName;
2650a96d7823Smrg
2651a96d7823Smrg    /* make a new block record, and add it to the end of the list */
2652a96d7823Smrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
2653a96d7823Smrg    if (!blockrec)
2654a96d7823Smrg	return AllocError;
2655a96d7823Smrg
2656a96d7823Smrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
2657a96d7823Smrg    bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
2658a96d7823Smrg    binfo->status = FS_LFWI_WAITING;
2659a96d7823Smrg
2660a96d7823Smrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2661a96d7823Smrg    {
2662a96d7823Smrg	_fs_pending_reply (conn);
2663a96d7823Smrg	return Suspended;
2664a96d7823Smrg    }
2665a96d7823Smrg
2666a96d7823Smrg    _fs_client_access (conn, client, FALSE);
2667a96d7823Smrg    _fs_client_resolution(conn);
2668a96d7823Smrg
2669a96d7823Smrg    /* send the request */
2670a96d7823Smrg    req.reqType = FS_ListFontsWithXInfo;
2671a96d7823Smrg    req.pad = 0;
2672a96d7823Smrg    req.maxNames = maxnames;
2673a96d7823Smrg    req.nbytes = len;
2674a96d7823Smrg    req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
2675a96d7823Smrg    _fs_add_req_log(conn, FS_ListFontsWithXInfo);
2676a96d7823Smrg    (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
2677a96d7823Smrg    (void) _fs_write_pad(conn, pattern, len);
2678a96d7823Smrg
2679a96d7823Smrg    blockrec->sequenceNumber = conn->current_seq;
2680a96d7823Smrg
2681a96d7823Smrg#ifdef NCD
2682a96d7823Smrg    if (configData.ExtendedFontDiags) {
2683a96d7823Smrg	char        buf[256];
2684a96d7823Smrg
2685a96d7823Smrg	memcpy(buf, pattern, MIN(256, len));
2686a96d7823Smrg	buf[MIN(256, len)] = '\0';
2687a96d7823Smrg	printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
2688a96d7823Smrg	       buf, fpe->name);
2689a96d7823Smrg    }
2690a96d7823Smrg#endif
2691a96d7823Smrg
2692a96d7823Smrg    _fs_prepare_for_reply (conn);
2693a96d7823Smrg    return Successful;
2694a96d7823Smrg}
2695a96d7823Smrg
2696a96d7823Smrg/* ARGSUSED */
2697a96d7823Smrgstatic int
2698a96d7823Smrgfs_next_list_with_info(pointer client, FontPathElementPtr fpe,
2699a96d7823Smrg		       char **namep, int *namelenp,
2700a96d7823Smrg		       FontInfoPtr *pFontInfo, int *numFonts,
2701a96d7823Smrg		       pointer private)
2702a96d7823Smrg{
2703a96d7823Smrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
2704a96d7823Smrg    FSBlockDataPtr	    blockrec;
2705a96d7823Smrg    FSBlockedListInfoPtr    binfo;
2706a96d7823Smrg    int			    err;
2707a96d7823Smrg
2708a96d7823Smrg    /* see if the result is already there */
2709a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2710a96d7823Smrg	if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
2711a96d7823Smrg	    break;
2712a96d7823Smrg
2713a96d7823Smrg    if (!blockrec)
2714a96d7823Smrg    {
2715a96d7823Smrg	/* The only good reason for not finding a blockrec would be if
2716a96d7823Smrg	   disconnect/reconnect to the font server wiped it out and the
2717a96d7823Smrg	   code that called us didn't do the right thing to create
2718a96d7823Smrg	   another one.  Under those circumstances, we need to return an
2719a96d7823Smrg	   error to prevent that code from attempting to interpret the
2720a96d7823Smrg	   information we don't return.  */
2721a96d7823Smrg	return BadFontName;
2722a96d7823Smrg    }
2723a96d7823Smrg
2724a96d7823Smrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
2725a96d7823Smrg
2726a96d7823Smrg    if (binfo->status == FS_LFWI_WAITING)
2727a96d7823Smrg	return Suspended;
2728a96d7823Smrg
2729a96d7823Smrg    *namep = binfo->name;
2730a96d7823Smrg    *namelenp = binfo->namelen;
2731a96d7823Smrg    *pFontInfo = &binfo->info;
2732a96d7823Smrg    *numFonts = binfo->remaining;
2733a96d7823Smrg
2734a96d7823Smrg    /* Restart reply processing from this font server */
2735a96d7823Smrg    conn_start_listening(conn);
2736a96d7823Smrg    if (fs_reply_ready (conn))
2737a96d7823Smrg	_fs_mark_block (conn, FS_COMPLETE_REPLY);
2738a96d7823Smrg
2739a96d7823Smrg    err = blockrec->errcode;
2740a96d7823Smrg    switch (binfo->status) {
2741a96d7823Smrg    case FS_LFWI_FINISHED:
2742a96d7823Smrg	_fs_remove_block_rec(conn, blockrec);
2743a96d7823Smrg	break;
2744a96d7823Smrg    case FS_LFWI_REPLY:
2745a96d7823Smrg	binfo->status = FS_LFWI_WAITING;
2746a96d7823Smrg	blockrec->errcode = StillWorking;
2747a96d7823Smrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
2748a96d7823Smrg	_fs_mark_block (conn, FS_PENDING_REPLY);
2749a96d7823Smrg	break;
2750a96d7823Smrg    }
2751a96d7823Smrg
2752a96d7823Smrg    return err;
2753a96d7823Smrg}
2754a96d7823Smrg
2755a96d7823Smrg/*
2756a96d7823Smrg * Called when client exits
2757a96d7823Smrg */
2758a96d7823Smrg
2759a96d7823Smrgstatic void
2760a96d7823Smrgfs_client_died(pointer client, FontPathElementPtr fpe)
2761a96d7823Smrg{
2762a96d7823Smrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
2763a96d7823Smrg    FSBlockDataPtr  blockrec,
2764a96d7823Smrg		    depending;
2765a96d7823Smrg    FSClientPtr	    *prev, cur;
2766a96d7823Smrg    fsFreeACReq	    freeac;
2767a96d7823Smrg
2768a96d7823Smrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2769a96d7823Smrg    {
2770a96d7823Smrg	if (cur->client == client) {
2771a96d7823Smrg	    freeac.reqType = FS_FreeAC;
2772a96d7823Smrg	    freeac.pad = 0;
2773a96d7823Smrg	    freeac.id = cur->acid;
2774a96d7823Smrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
2775a96d7823Smrg	    _fs_add_req_log(conn, FS_FreeAC);
2776a96d7823Smrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2777a96d7823Smrg	    *prev = cur->next;
2778a96d7823Smrg	    free (cur);
2779a96d7823Smrg	    break;
2780a96d7823Smrg	}
2781a96d7823Smrg    }
2782a96d7823Smrg    /* find a pending requests */
2783a96d7823Smrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2784a96d7823Smrg	if (blockrec->client == client)
2785a96d7823Smrg	    break;
2786a96d7823Smrg
2787a96d7823Smrg    if (!blockrec)
2788a96d7823Smrg	return;
2789a96d7823Smrg
2790a96d7823Smrg    /* replace the client pointers in this block rec with the chained one */
2791a96d7823Smrg    if ((depending = blockrec->depending))
2792a96d7823Smrg    {
2793a96d7823Smrg	blockrec->client = depending->client;
2794a96d7823Smrg	blockrec->depending = depending->depending;
2795a96d7823Smrg	blockrec = depending;
2796a96d7823Smrg    }
2797a96d7823Smrg    fs_abort_blockrec(conn, blockrec);
2798a96d7823Smrg}
2799a96d7823Smrg
2800a96d7823Smrgstatic void
2801a96d7823Smrg_fs_client_access (FSFpePtr conn, pointer client, Bool sync)
2802a96d7823Smrg{
2803a96d7823Smrg    FSClientPtr	*prev,	    cur;
2804a96d7823Smrg    fsCreateACReq	    crac;
2805a96d7823Smrg    fsSetAuthorizationReq   setac;
2806a96d7823Smrg    char		    *authorizations;
2807a96d7823Smrg    int			    authlen;
2808a96d7823Smrg    Bool		    new_cur = FALSE;
2809a96d7823Smrg    char		    padding[4] = { 0, 0, 0, 0 };
2810a96d7823Smrg
2811a96d7823Smrg#ifdef DEBUG
2812a96d7823Smrg    if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
2813a96d7823Smrg    {
2814a96d7823Smrg	fprintf (stderr, "Sending requests without a connection\n");
2815a96d7823Smrg    }
2816a96d7823Smrg#endif
2817a96d7823Smrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2818a96d7823Smrg    {
2819a96d7823Smrg	if (cur->client == client)
2820a96d7823Smrg	{
2821a96d7823Smrg	    if (prev != &conn->clients)
2822a96d7823Smrg	    {
2823a96d7823Smrg		*prev = cur->next;
2824a96d7823Smrg		cur->next = conn->clients;
2825a96d7823Smrg		conn->clients = cur;
2826a96d7823Smrg	    }
2827a96d7823Smrg	    break;
2828a96d7823Smrg	}
2829a96d7823Smrg    }
2830a96d7823Smrg    if (!cur)
2831a96d7823Smrg    {
2832a96d7823Smrg	cur = malloc (sizeof (FSClientRec));
2833a96d7823Smrg	if (!cur)
2834a96d7823Smrg	    return;
2835a96d7823Smrg	cur->client = client;
2836a96d7823Smrg	cur->next = conn->clients;
2837a96d7823Smrg	conn->clients = cur;
2838a96d7823Smrg	cur->acid = GetNewFontClientID ();
2839a96d7823Smrg	new_cur = TRUE;
2840a96d7823Smrg    }
2841a96d7823Smrg    if (new_cur || cur->auth_generation != client_auth_generation(client))
2842a96d7823Smrg    {
2843a96d7823Smrg	if (!new_cur)
2844a96d7823Smrg	{
2845a96d7823Smrg	    fsFreeACReq	freeac;
2846a96d7823Smrg	    freeac.reqType = FS_FreeAC;
2847a96d7823Smrg	    freeac.pad = 0;
2848a96d7823Smrg	    freeac.id = cur->acid;
2849a96d7823Smrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
2850a96d7823Smrg	    _fs_add_req_log(conn, FS_FreeAC);
2851a96d7823Smrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2852a96d7823Smrg	}
2853a96d7823Smrg	crac.reqType = FS_CreateAC;
2854a96d7823Smrg	crac.num_auths = set_font_authorizations(&authorizations, &authlen,
2855a96d7823Smrg						 client);
2856a96d7823Smrg	/* Work around bug in xfs versions up through modular release 1.0.8
2857a96d7823Smrg	   which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
2858a96d7823Smrg	if (crac.num_auths == 0) {
2859a96d7823Smrg	    authorizations = padding;
2860a96d7823Smrg	    authlen = 4;
2861a96d7823Smrg	}
2862a96d7823Smrg	crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
2863a96d7823Smrg	crac.acid = cur->acid;
2864a96d7823Smrg	_fs_add_req_log(conn, FS_CreateAC);
2865a96d7823Smrg	_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
2866fd60135fSmrg	_fs_write_pad(conn, authorizations, authlen);
2867a96d7823Smrg	/* ignore reply; we don't even care about it */
2868a96d7823Smrg	conn->curacid = 0;
2869a96d7823Smrg	cur->auth_generation = client_auth_generation(client);
2870a96d7823Smrg    }
2871a96d7823Smrg    if (conn->curacid != cur->acid)
2872a96d7823Smrg    {
2873a96d7823Smrg    	setac.reqType = FS_SetAuthorization;
2874a96d7823Smrg	setac.pad = 0;
2875a96d7823Smrg    	setac.length = sizeof (fsSetAuthorizationReq) >> 2;
2876a96d7823Smrg    	setac.id = cur->acid;
2877a96d7823Smrg    	_fs_add_req_log(conn, FS_SetAuthorization);
2878a96d7823Smrg    	_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
2879a96d7823Smrg	conn->curacid = cur->acid;
2880a96d7823Smrg    }
2881a96d7823Smrg}
2882a96d7823Smrg
2883a96d7823Smrg/*
2884a96d7823Smrg * Poll a pending connect
2885a96d7823Smrg */
2886a96d7823Smrg
2887a96d7823Smrgstatic int
2888a96d7823Smrg_fs_check_connect (FSFpePtr conn)
2889a96d7823Smrg{
2890a96d7823Smrg    int	    ret;
2891a96d7823Smrg
2892a96d7823Smrg    ret = _fs_poll_connect (conn->trans_conn, 0);
2893a96d7823Smrg    switch (ret) {
2894a96d7823Smrg    case FSIO_READY:
2895a96d7823Smrg	conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
2896a96d7823Smrg	conn_start_listening(conn);
2897a96d7823Smrg	break;
2898a96d7823Smrg    case FSIO_BLOCK:
2899a96d7823Smrg	break;
2900a96d7823Smrg    }
2901a96d7823Smrg    return ret;
2902a96d7823Smrg}
2903a96d7823Smrg
2904a96d7823Smrg/*
2905a96d7823Smrg * Return an FSIO status while waiting for the completed connection
2906a96d7823Smrg * reply to arrive
2907a96d7823Smrg */
2908a96d7823Smrg
2909a96d7823Smrgstatic fsConnSetup *
2910a96d7823Smrg_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
2911a96d7823Smrg{
2912a96d7823Smrg    int			ret;
2913a96d7823Smrg    char		*data;
2914a96d7823Smrg    int			headlen;
2915a96d7823Smrg    int			len;
2916a96d7823Smrg    fsConnSetup		*setup;
2917a96d7823Smrg    fsConnSetupAccept	*accept;
2918a96d7823Smrg
2919a96d7823Smrg    ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
2920a96d7823Smrg    if (ret != FSIO_READY)
2921a96d7823Smrg    {
2922a96d7823Smrg	*error = ret;
2923a96d7823Smrg	return 0;
2924a96d7823Smrg    }
2925a96d7823Smrg
2926a96d7823Smrg    setup = (fsConnSetup *) data;
2927a96d7823Smrg    if (setup->major_version > FS_PROTOCOL)
2928a96d7823Smrg    {
2929a96d7823Smrg	*error = FSIO_ERROR;
2930a96d7823Smrg	return 0;
2931a96d7823Smrg    }
2932a96d7823Smrg
2933a96d7823Smrg    headlen = (SIZEOF (fsConnSetup) +
2934a96d7823Smrg	       (setup->alternate_len << 2) +
2935a96d7823Smrg	       (setup->auth_len << 2));
2936a96d7823Smrg    /* On anything but Success, no extra data is sent */
2937a96d7823Smrg    if (setup->status != AuthSuccess)
2938a96d7823Smrg    {
2939a96d7823Smrg	len = headlen;
2940a96d7823Smrg    }
2941a96d7823Smrg    else
2942a96d7823Smrg    {
2943a96d7823Smrg	ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
2944a96d7823Smrg	if (ret != FSIO_READY)
2945a96d7823Smrg	{
2946a96d7823Smrg	    *error = ret;
2947a96d7823Smrg	    return 0;
2948a96d7823Smrg	}
2949a96d7823Smrg	setup = (fsConnSetup *) data;
2950a96d7823Smrg	accept = (fsConnSetupAccept *) (data + headlen);
2951a96d7823Smrg	len = headlen + (accept->length << 2);
2952a96d7823Smrg    }
2953a96d7823Smrg    ret = _fs_start_read (conn, len, &data);
2954a96d7823Smrg    if (ret != FSIO_READY)
2955a96d7823Smrg    {
2956a96d7823Smrg	*error = ret;
2957a96d7823Smrg	return 0;
2958a96d7823Smrg    }
2959a96d7823Smrg    *setup_len = len;
2960a96d7823Smrg    return (fsConnSetup *) data;
2961a96d7823Smrg}
2962a96d7823Smrg
2963a96d7823Smrgstatic int
2964a96d7823Smrg_fs_send_conn_client_prefix (FSFpePtr conn)
2965a96d7823Smrg{
2966a96d7823Smrg    fsConnClientPrefix	req;
2967a96d7823Smrg    int			endian;
2968a96d7823Smrg    int			ret;
2969a96d7823Smrg
2970a96d7823Smrg    /* send setup prefix */
2971a96d7823Smrg    endian = 1;
2972a96d7823Smrg    if (*(char *) &endian)
2973a96d7823Smrg	req.byteOrder = 'l';
2974a96d7823Smrg    else
2975a96d7823Smrg	req.byteOrder = 'B';
2976a96d7823Smrg
2977a96d7823Smrg    req.major_version = FS_PROTOCOL;
2978a96d7823Smrg    req.minor_version = FS_PROTOCOL_MINOR;
2979a96d7823Smrg
2980a96d7823Smrg/* XXX add some auth info here */
2981a96d7823Smrg    req.num_auths = 0;
2982a96d7823Smrg    req.auth_len = 0;
2983a96d7823Smrg    ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
2984a96d7823Smrg    if (ret != FSIO_READY)
2985a96d7823Smrg	return FSIO_ERROR;
2986a96d7823Smrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
2987a96d7823Smrg    return ret;
2988a96d7823Smrg}
2989a96d7823Smrg
2990a96d7823Smrgstatic int
2991a96d7823Smrg_fs_recv_conn_setup (FSFpePtr conn)
2992a96d7823Smrg{
2993a96d7823Smrg    int			ret = FSIO_ERROR;
2994a96d7823Smrg    fsConnSetup		*setup;
2995a96d7823Smrg    FSFpeAltPtr		alts;
2996a96d7823Smrg    unsigned int	i, alt_len;
2997a96d7823Smrg    int			setup_len;
2998a96d7823Smrg    char		*alt_save, *alt_names;
2999a96d7823Smrg
3000a96d7823Smrg    setup = _fs_get_conn_setup (conn, &ret, &setup_len);
3001a96d7823Smrg    if (!setup)
3002a96d7823Smrg	return ret;
3003a96d7823Smrg    conn->current_seq = 0;
3004a96d7823Smrg    conn->fsMajorVersion = setup->major_version;
3005a96d7823Smrg    /*
3006a96d7823Smrg     * Create an alternate list from the initial server, but
3007a96d7823Smrg     * don't chain looking for alternates.
3008a96d7823Smrg     */
3009a96d7823Smrg    if (conn->alternate == 0)
3010a96d7823Smrg    {
3011a96d7823Smrg	/*
3012a96d7823Smrg	 * free any existing alternates list, allowing the list to
3013a96d7823Smrg	 * be updated
3014a96d7823Smrg	 */
3015a96d7823Smrg	if (conn->alts)
3016a96d7823Smrg	{
3017a96d7823Smrg	    free (conn->alts);
3018a96d7823Smrg	    conn->alts = 0;
3019a96d7823Smrg	    conn->numAlts = 0;
3020a96d7823Smrg	}
3021a96d7823Smrg	if (setup->num_alternates)
3022a96d7823Smrg	{
3023a96d7823Smrg	    size_t alt_name_len = setup->alternate_len << 2;
3024a96d7823Smrg	    alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
3025a96d7823Smrg			   alt_name_len);
3026a96d7823Smrg	    if (alts)
3027a96d7823Smrg	    {
3028a96d7823Smrg		alt_names = (char *) (setup + 1);
3029a96d7823Smrg		alt_save = (char *) (alts + setup->num_alternates);
3030a96d7823Smrg		for (i = 0; i < setup->num_alternates; i++)
3031a96d7823Smrg		{
3032a96d7823Smrg		    alts[i].subset = alt_names[0];
3033a96d7823Smrg		    alt_len = alt_names[1];
3034a96d7823Smrg		    if (alt_len >= alt_name_len) {
3035a96d7823Smrg			/*
3036a96d7823Smrg			 * Length is longer than setup->alternate_len
3037a96d7823Smrg			 * told us to allocate room for, assume entire
3038a96d7823Smrg			 * alternate list is corrupted.
3039a96d7823Smrg			 */
3040a96d7823Smrg#ifdef DEBUG
3041a96d7823Smrg			fprintf (stderr,
3042a96d7823Smrg				 "invalid alt list (length %lx >= %lx)\n",
3043a96d7823Smrg				 (long) alt_len, (long) alt_name_len);
3044a96d7823Smrg#endif
3045a96d7823Smrg			free(alts);
3046a96d7823Smrg			return FSIO_ERROR;
3047a96d7823Smrg		    }
3048a96d7823Smrg		    alts[i].name = alt_save;
3049a96d7823Smrg		    memcpy (alt_save, alt_names + 2, alt_len);
3050a96d7823Smrg		    alt_save[alt_len] = '\0';
3051a96d7823Smrg		    alt_save += alt_len + 1;
3052a96d7823Smrg		    alt_name_len -= alt_len + 1;
3053a96d7823Smrg		    alt_names += _fs_pad_length (alt_len + 2);
3054a96d7823Smrg		}
3055a96d7823Smrg		conn->numAlts = setup->num_alternates;
3056a96d7823Smrg		conn->alts = alts;
3057a96d7823Smrg	    }
3058a96d7823Smrg	}
3059a96d7823Smrg    }
3060a96d7823Smrg    _fs_done_read (conn, setup_len);
3061a96d7823Smrg    if (setup->status != AuthSuccess)
3062a96d7823Smrg	return FSIO_ERROR;
3063a96d7823Smrg    return FSIO_READY;
3064a96d7823Smrg}
3065a96d7823Smrg
3066a96d7823Smrgstatic int
3067a96d7823Smrg_fs_open_server (FSFpePtr conn)
3068a96d7823Smrg{
3069a96d7823Smrg    int	    ret;
3070a96d7823Smrg    char    *servername;
3071a96d7823Smrg
3072a96d7823Smrg    if (conn->alternate == 0)
3073a96d7823Smrg	servername = conn->servername;
3074a96d7823Smrg    else
3075a96d7823Smrg	servername = conn->alts[conn->alternate-1].name;
3076a96d7823Smrg    conn->trans_conn = _fs_connect (servername, &ret);
3077a96d7823Smrg    conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
3078a96d7823Smrg    return ret;
3079a96d7823Smrg}
3080a96d7823Smrg
3081a96d7823Smrgstatic char *
3082a96d7823Smrg_fs_catalog_name (char *servername)
3083a96d7823Smrg{
3084a96d7823Smrg    char    *sp;
3085a96d7823Smrg
3086a96d7823Smrg    sp = strchr (servername, '/');
3087a96d7823Smrg    if (!sp)
3088a96d7823Smrg	return 0;
3089a96d7823Smrg    return strrchr (sp + 1, '/');
3090a96d7823Smrg}
3091a96d7823Smrg
3092a96d7823Smrgstatic int
3093a96d7823Smrg_fs_send_init_packets (FSFpePtr conn)
3094a96d7823Smrg{
3095a96d7823Smrg    fsSetResolutionReq	    srreq;
3096a96d7823Smrg    fsSetCataloguesReq	    screq;
3097a96d7823Smrg    int			    num_cats,
3098a96d7823Smrg			    clen;
3099a96d7823Smrg    char		    *catalogues;
3100a96d7823Smrg    char		    *cat;
3101a96d7823Smrg    char		    len;
3102a96d7823Smrg    char		    *end;
3103a96d7823Smrg    int			    num_res;
3104a96d7823Smrg    FontResolutionPtr	    res;
3105a96d7823Smrg
3106a96d7823Smrg#define	CATALOGUE_SEP	'+'
3107a96d7823Smrg
3108a96d7823Smrg    res = GetClientResolutions(&num_res);
3109a96d7823Smrg    if (num_res)
3110a96d7823Smrg    {
3111a96d7823Smrg	srreq.reqType = FS_SetResolution;
3112a96d7823Smrg	srreq.num_resolutions = num_res;
3113a96d7823Smrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
3114a96d7823Smrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
3115a96d7823Smrg
3116a96d7823Smrg	_fs_add_req_log(conn, FS_SetResolution);
3117a96d7823Smrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
3118a96d7823Smrg	    return FSIO_ERROR;
3119a96d7823Smrg	if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
3120a96d7823Smrg	    return FSIO_ERROR;
3121a96d7823Smrg    }
3122a96d7823Smrg
3123a96d7823Smrg    catalogues = 0;
3124a96d7823Smrg    if (conn->alternate != 0)
3125a96d7823Smrg	catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
3126a96d7823Smrg    if (!catalogues)
3127a96d7823Smrg	catalogues = _fs_catalog_name (conn->servername);
3128a96d7823Smrg
3129a96d7823Smrg    if (!catalogues)
3130a96d7823Smrg    {
3131a96d7823Smrg	conn->has_catalogues = FALSE;
3132a96d7823Smrg	return FSIO_READY;
3133a96d7823Smrg    }
3134a96d7823Smrg    conn->has_catalogues = TRUE;
3135a96d7823Smrg
3136a96d7823Smrg    /* turn cats into counted list */
3137a96d7823Smrg    catalogues++;
3138a96d7823Smrg
3139a96d7823Smrg    cat = catalogues;
3140a96d7823Smrg    num_cats = 0;
3141a96d7823Smrg    clen = 0;
3142a96d7823Smrg    while (*cat)
3143a96d7823Smrg    {
3144a96d7823Smrg	num_cats++;
3145a96d7823Smrg	end = strchr(cat, CATALOGUE_SEP);
3146a96d7823Smrg	if (!end)
3147a96d7823Smrg	    end = cat + strlen (cat);
3148a96d7823Smrg	clen += (end - cat) + 1;	/* length byte + string */
3149a96d7823Smrg	cat = end;
3150a96d7823Smrg    }
3151a96d7823Smrg
3152a96d7823Smrg    screq.reqType = FS_SetCatalogues;
3153a96d7823Smrg    screq.num_catalogues = num_cats;
3154a96d7823Smrg    screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
3155a96d7823Smrg
3156a96d7823Smrg    _fs_add_req_log(conn, FS_SetCatalogues);
3157a96d7823Smrg    if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
3158a96d7823Smrg	return FSIO_ERROR;
3159a96d7823Smrg
3160a96d7823Smrg    while (*cat)
3161a96d7823Smrg    {
3162a96d7823Smrg	num_cats++;
3163a96d7823Smrg	end = strchr(cat, CATALOGUE_SEP);
3164a96d7823Smrg	if (!end)
3165a96d7823Smrg	    end = cat + strlen (cat);
3166a96d7823Smrg	len = end - cat;
3167a96d7823Smrg	if (_fs_write (conn, &len, 1) != FSIO_READY)
3168a96d7823Smrg	    return FSIO_ERROR;
3169a96d7823Smrg	if (_fs_write (conn, cat, (int) len) != FSIO_READY)
3170a96d7823Smrg	    return FSIO_ERROR;
3171a96d7823Smrg	cat = end;
3172a96d7823Smrg    }
3173a96d7823Smrg
3174a96d7823Smrg    if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
3175a96d7823Smrg	return FSIO_ERROR;
3176a96d7823Smrg
3177a96d7823Smrg    return FSIO_READY;
3178a96d7823Smrg}
3179a96d7823Smrg
3180a96d7823Smrgstatic int
3181a96d7823Smrg_fs_send_cat_sync (FSFpePtr conn)
3182a96d7823Smrg{
3183a96d7823Smrg    fsListCataloguesReq	    lcreq;
3184a96d7823Smrg
3185a96d7823Smrg    /*
3186a96d7823Smrg     * now sync up with the font server, to see if an error was generated
3187a96d7823Smrg     * by a bogus catalogue
3188a96d7823Smrg     */
3189a96d7823Smrg    lcreq.reqType = FS_ListCatalogues;
3190a96d7823Smrg    lcreq.data = 0;
3191a96d7823Smrg    lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
3192a96d7823Smrg    lcreq.maxNames = 0;
3193a96d7823Smrg    lcreq.nbytes = 0;
3194a96d7823Smrg    lcreq.pad2 = 0;
3195a96d7823Smrg    _fs_add_req_log(conn, FS_SetCatalogues);
3196a96d7823Smrg    if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
3197a96d7823Smrg	return FSIO_ERROR;
3198a96d7823Smrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
3199a96d7823Smrg    return FSIO_READY;
3200a96d7823Smrg}
3201a96d7823Smrg
3202a96d7823Smrgstatic int
3203a96d7823Smrg_fs_recv_cat_sync (FSFpePtr conn)
3204a96d7823Smrg{
3205a96d7823Smrg    fsGenericReply  *reply;
3206a96d7823Smrg    fsError	    *error;
3207a96d7823Smrg    int		    err;
3208a96d7823Smrg    int		    ret;
3209a96d7823Smrg
3210a96d7823Smrg    reply = fs_get_reply (conn, &err);
3211a96d7823Smrg    if (!reply)
3212a96d7823Smrg	return err;
3213a96d7823Smrg
3214a96d7823Smrg    ret = FSIO_READY;
3215a96d7823Smrg    if (reply->type == FS_Error)
3216a96d7823Smrg    {
3217a96d7823Smrg	error = (fsError *) reply;
3218a96d7823Smrg	if (error->major_opcode == FS_SetCatalogues)
3219a96d7823Smrg	    ret = FSIO_ERROR;
3220a96d7823Smrg    }
3221a96d7823Smrg    _fs_done_read (conn, reply->length << 2);
3222a96d7823Smrg    return ret;
3223a96d7823Smrg}
3224a96d7823Smrg
3225a96d7823Smrgstatic void
3226a96d7823Smrg_fs_close_server (FSFpePtr conn)
3227a96d7823Smrg{
3228a96d7823Smrg    _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
3229a96d7823Smrg    if (conn->trans_conn)
3230a96d7823Smrg    {
3231a96d7823Smrg	_FontTransClose (conn->trans_conn);
3232a96d7823Smrg	conn->trans_conn = 0;
3233a96d7823Smrg	_fs_io_reinit (conn);
3234a96d7823Smrg    }
3235a96d7823Smrg    if (conn->fs_fd >= 0)
3236a96d7823Smrg    {
3237a96d7823Smrg	conn_stop_listening(conn);
3238a96d7823Smrg	conn->fs_fd = -1;
3239a96d7823Smrg    }
3240a96d7823Smrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
3241a96d7823Smrg}
3242a96d7823Smrg
3243a96d7823Smrgstatic int
3244a96d7823Smrg_fs_do_setup_connection (FSFpePtr conn)
3245a96d7823Smrg{
3246a96d7823Smrg    int	    ret;
3247a96d7823Smrg
3248a96d7823Smrg    do
3249a96d7823Smrg    {
3250a96d7823Smrg#ifdef DEBUG
3251a96d7823Smrg	fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
3252a96d7823Smrg#endif
3253a96d7823Smrg	switch (conn->fs_conn_state) {
3254a96d7823Smrg	case FS_CONN_UNCONNECTED:
3255a96d7823Smrg	    ret = _fs_open_server (conn);
3256a96d7823Smrg	    if (ret == FSIO_BLOCK)
3257a96d7823Smrg		conn->fs_conn_state = FS_CONN_CONNECTING;
3258a96d7823Smrg	    break;
3259a96d7823Smrg	case FS_CONN_CONNECTING:
3260a96d7823Smrg	    ret = _fs_check_connect (conn);
3261a96d7823Smrg	    break;
3262a96d7823Smrg	case FS_CONN_CONNECTED:
3263a96d7823Smrg	    ret = _fs_send_conn_client_prefix (conn);
3264a96d7823Smrg	    break;
3265a96d7823Smrg	case FS_CONN_SENT_PREFIX:
3266a96d7823Smrg	    ret = _fs_recv_conn_setup (conn);
3267a96d7823Smrg	    break;
3268a96d7823Smrg	case FS_CONN_RECV_INIT:
3269a96d7823Smrg	    ret = _fs_send_init_packets (conn);
3270a96d7823Smrg	    if (conn->has_catalogues)
3271a96d7823Smrg		ret = _fs_send_cat_sync (conn);
3272a96d7823Smrg	    break;
3273a96d7823Smrg	case FS_CONN_SENT_CAT:
3274a96d7823Smrg	    if (conn->has_catalogues)
3275a96d7823Smrg		ret = _fs_recv_cat_sync (conn);
3276a96d7823Smrg	    else
3277a96d7823Smrg		ret = FSIO_READY;
3278a96d7823Smrg	    break;
3279a96d7823Smrg	default:
3280a96d7823Smrg	    ret = FSIO_READY;
3281a96d7823Smrg	    break;
3282a96d7823Smrg	}
3283a96d7823Smrg	switch (ret) {
3284a96d7823Smrg	case FSIO_READY:
3285a96d7823Smrg	    if (conn->fs_conn_state < FS_CONN_RUNNING)
3286a96d7823Smrg		conn->fs_conn_state++;
3287a96d7823Smrg	    break;
3288a96d7823Smrg	case FSIO_BLOCK:
3289a96d7823Smrg	    if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
3290a96d7823Smrg		break;
3291a96d7823Smrg	    ret = FSIO_ERROR;
3292a96d7823Smrg	    /* fall through... */
3293a96d7823Smrg	case FSIO_ERROR:
3294a96d7823Smrg	    _fs_close_server (conn);
3295a96d7823Smrg	    /*
3296a96d7823Smrg	     * Try the next alternate
3297a96d7823Smrg	     */
3298a96d7823Smrg	    if (conn->alternate < conn->numAlts)
3299a96d7823Smrg	    {
3300a96d7823Smrg		conn->alternate++;
3301a96d7823Smrg		ret = FSIO_READY;
3302a96d7823Smrg	    }
3303a96d7823Smrg	    else
3304a96d7823Smrg		conn->alternate = 0;
3305a96d7823Smrg	    break;
3306a96d7823Smrg	}
3307a96d7823Smrg    } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
3308a96d7823Smrg    if (ret == FSIO_READY)
3309a96d7823Smrg	conn->generation = ++generationCount;
3310a96d7823Smrg    return ret;
3311a96d7823Smrg}
3312a96d7823Smrg
3313a96d7823Smrgstatic int
3314a96d7823Smrg_fs_wait_connect (FSFpePtr conn)
3315a96d7823Smrg{
3316a96d7823Smrg    int	    ret;
3317a96d7823Smrg
3318a96d7823Smrg    for (;;)
3319a96d7823Smrg    {
3320a96d7823Smrg	ret = _fs_do_setup_connection (conn);
3321a96d7823Smrg	if (ret != FSIO_BLOCK)
3322a96d7823Smrg	    break;
3323a96d7823Smrg	if (conn->fs_conn_state <= FS_CONN_CONNECTING)
3324a96d7823Smrg	    ret = _fs_poll_connect (conn->trans_conn, 1000);
3325a96d7823Smrg	else
3326a96d7823Smrg	    ret = _fs_wait_for_readable (conn, 1000);
3327a96d7823Smrg	if (ret == FSIO_ERROR)
3328a96d7823Smrg	    break;
3329a96d7823Smrg    }
3330a96d7823Smrg    return ret;
3331a96d7823Smrg}
3332a96d7823Smrg
3333a96d7823Smrg/*
3334a96d7823Smrg * Poll a connection in the process of reconnecting
3335a96d7823Smrg */
3336a96d7823Smrgstatic void
3337a96d7823Smrg_fs_check_reconnect (FSFpePtr conn)
3338a96d7823Smrg{
3339a96d7823Smrg    int	    ret;
3340a96d7823Smrg
3341a96d7823Smrg    ret = _fs_do_setup_connection (conn);
3342a96d7823Smrg    switch (ret) {
3343a96d7823Smrg    case FSIO_READY:
3344a96d7823Smrg	_fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
3345a96d7823Smrg	_fs_restart_connection (conn);
3346a96d7823Smrg	break;
3347a96d7823Smrg    case FSIO_BLOCK:
3348a96d7823Smrg	break;
3349a96d7823Smrg    case FSIO_ERROR:
3350a96d7823Smrg	conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
3351a96d7823Smrg	break;
3352a96d7823Smrg    }
3353a96d7823Smrg}
3354a96d7823Smrg
3355a96d7823Smrg/*
3356a96d7823Smrg * Start the reconnection process
3357a96d7823Smrg */
3358a96d7823Smrgstatic void
3359a96d7823Smrg_fs_start_reconnect (FSFpePtr conn)
3360a96d7823Smrg{
3361a96d7823Smrg    if (conn->blockState & FS_RECONNECTING)
3362a96d7823Smrg	return;
3363a96d7823Smrg    conn->alternate = 0;
3364a96d7823Smrg    _fs_mark_block (conn, FS_RECONNECTING);
3365a96d7823Smrg    _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
3366a96d7823Smrg    _fs_check_reconnect (conn);
3367a96d7823Smrg}
3368a96d7823Smrg
3369a96d7823Smrg
3370a96d7823Smrgstatic FSFpePtr
3371a96d7823Smrg_fs_init_conn (const char *servername, FontPathElementPtr fpe)
3372a96d7823Smrg{
3373a96d7823Smrg    FSFpePtr	conn;
3374c7b4381aSmrg    size_t	snlen = strlen (servername) + 1;
3375a96d7823Smrg
3376c7b4381aSmrg    conn = calloc (1, sizeof (FSFpeRec) + snlen);
3377a96d7823Smrg    if (!conn)
3378a96d7823Smrg	return 0;
3379a96d7823Smrg    if (!_fs_io_init (conn))
3380a96d7823Smrg    {
3381a96d7823Smrg	free (conn);
3382a96d7823Smrg	return 0;
3383a96d7823Smrg    }
3384a96d7823Smrg    conn->servername = (char *) (conn + 1);
3385a96d7823Smrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
3386a96d7823Smrg    conn->fs_fd = -1;
3387a96d7823Smrg    conn->fpe = fpe;
3388c7b4381aSmrg    strlcpy (conn->servername, servername, snlen);
3389a96d7823Smrg    return conn;
3390a96d7823Smrg}
3391a96d7823Smrg
3392a96d7823Smrgstatic void
3393a96d7823Smrg_fs_free_conn (FSFpePtr conn)
3394a96d7823Smrg{
3395a96d7823Smrg    _fs_close_server (conn);
3396a96d7823Smrg    _fs_io_fini (conn);
3397a96d7823Smrg    if (conn->alts)
3398a96d7823Smrg	free (conn->alts);
3399a96d7823Smrg    free (conn);
3400a96d7823Smrg}
3401a96d7823Smrg
3402a96d7823Smrg/*
3403a96d7823Smrg * called at server init time
3404a96d7823Smrg */
3405a96d7823Smrg
3406a96d7823Smrgstatic const xfont2_fpe_funcs_rec fs_fpe_funcs = {
3407a96d7823Smrg	.version = XFONT2_FPE_FUNCS_VERSION,
3408a96d7823Smrg	.name_check = fs_name_check,
3409a96d7823Smrg	.init_fpe = fs_init_fpe,
3410a96d7823Smrg	.free_fpe = fs_free_fpe,
3411a96d7823Smrg	.reset_fpe = fs_reset_fpe,
3412a96d7823Smrg	.open_font = fs_open_font,
3413a96d7823Smrg	.close_font = fs_close_font,
3414a96d7823Smrg	.list_fonts = fs_list_fonts,
3415a96d7823Smrg	.start_list_fonts_with_info = fs_start_list_with_info,
3416a96d7823Smrg	.list_next_font_with_info = fs_next_list_with_info,
3417a96d7823Smrg	.wakeup_fpe = fs_wakeup,
3418a96d7823Smrg	.client_died = fs_client_died,
3419a96d7823Smrg	.load_glyphs = _fs_load_glyphs,
3420a96d7823Smrg	.start_list_fonts_and_aliases = (StartLaFunc) 0,
3421a96d7823Smrg	.list_next_font_or_alias = (NextLaFunc) 0,
3422a96d7823Smrg	.set_path_hook = (SetPathFunc) 0
3423a96d7823Smrg};
3424a96d7823Smrg
3425a96d7823Smrgvoid
3426a96d7823Smrgfs_register_fpe_functions(void)
3427a96d7823Smrg{
3428a96d7823Smrg    register_fpe_funcs(&fs_fpe_funcs);
3429a96d7823Smrg}
3430