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