fserve.c revision 7673729a
123a0898aSmrg/*
223a0898aSmrg
323a0898aSmrgCopyright 1990, 1998  The Open Group
423a0898aSmrg
523a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
623a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
723a0898aSmrgthe above copyright notice appear in all copies and that both that
823a0898aSmrgcopyright notice and this permission notice appear in supporting
923a0898aSmrgdocumentation.
1023a0898aSmrg
1123a0898aSmrgThe above copyright notice and this permission notice shall be included in
1223a0898aSmrgall copies or substantial portions of the Software.
1323a0898aSmrg
1423a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1523a0898aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1623a0898aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1723a0898aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1823a0898aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1923a0898aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2023a0898aSmrg
2123a0898aSmrgExcept as contained in this notice, the name of The Open Group shall not be
2223a0898aSmrgused in advertising or otherwise to promote the sale, use or other dealings
2323a0898aSmrgin this Software without prior written authorization from The Open Group.
2423a0898aSmrg
2523a0898aSmrg*/
2623a0898aSmrg
2723a0898aSmrg/*
2823a0898aSmrg * Copyright 1990 Network Computing Devices
2923a0898aSmrg *
3023a0898aSmrg * Permission to use, copy, modify, distribute, and sell this software and
3123a0898aSmrg * its documentation for any purpose is hereby granted without fee, provided
3223a0898aSmrg * that the above copyright notice appear in all copies and that both that
3323a0898aSmrg * copyright notice and this permission notice appear in supporting
3423a0898aSmrg * documentation, and that the names of Network Computing Devices, or Digital
3523a0898aSmrg * not be used in advertising or publicity pertaining to distribution
3623a0898aSmrg * of the software without specific, written prior permission.
3723a0898aSmrg *
3823a0898aSmrg * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
3923a0898aSmrg * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
4023a0898aSmrg * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
4123a0898aSmrg * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
4223a0898aSmrg * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
4323a0898aSmrg * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4423a0898aSmrg * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
4523a0898aSmrg * THIS SOFTWARE.
4623a0898aSmrg *
4723a0898aSmrg * Author:  	Dave Lemke, Network Computing Devices, Inc
4823a0898aSmrg */
4923a0898aSmrg/*
5023a0898aSmrg * font server specific font access
5123a0898aSmrg */
5223a0898aSmrg
5323a0898aSmrg#ifdef HAVE_CONFIG_H
5423a0898aSmrg#include <config.h>
5523a0898aSmrg#endif
5623a0898aSmrg
5723a0898aSmrg#ifdef WIN32
5823a0898aSmrg#define _WILLWINSOCK_
5923a0898aSmrg#endif
6023a0898aSmrg#define FONT_t
6123a0898aSmrg#define TRANS_CLIENT
6223a0898aSmrg#include	"X11/Xtrans/Xtrans.h"
6323a0898aSmrg#include	"X11/Xpoll.h"
6423a0898aSmrg#include	<X11/fonts/FS.h>
6523a0898aSmrg#include	<X11/fonts/FSproto.h>
6623a0898aSmrg#include	<X11/X.h>
6723a0898aSmrg#include	<X11/Xos.h>
6823a0898aSmrg#include	<X11/fonts/fontmisc.h>
6923a0898aSmrg#include	<X11/fonts/fontstruct.h>
7023a0898aSmrg#include	"fservestr.h"
7123a0898aSmrg#include	<X11/fonts/fontutil.h>
7223a0898aSmrg#include	<errno.h>
737673729aSmrg#include	<limits.h>
7423a0898aSmrg
7523a0898aSmrg#include	<time.h>
7623a0898aSmrg#define Time_t time_t
7723a0898aSmrg
7823a0898aSmrg#ifdef NCD
7923a0898aSmrg#include	<ncd/nvram.h>
8023a0898aSmrg#endif
8123a0898aSmrg
8223a0898aSmrg#include <stddef.h>
8323a0898aSmrg
8423a0898aSmrg#ifndef MIN
8523a0898aSmrg#define MIN(a,b)    ((a)<(b)?(a):(b))
8623a0898aSmrg#endif
8723a0898aSmrg#define TimeCmp(a,c,b)	((int) ((a) - (b)) c 0)
8841c30155Smrg
8923a0898aSmrg#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
9023a0898aSmrg			     (pci)->rightSideBearing || \
9123a0898aSmrg			     (pci)->ascent || \
9223a0898aSmrg			     (pci)->descent || \
9323a0898aSmrg			     (pci)->characterWidth)
9423a0898aSmrg
959d21a897Sspz/*
969d21a897Sspz * SIZEOF(r) is in bytes, length fields in the protocol are in 32-bit words,
979d21a897Sspz * so this converts for doing size comparisons.
989d21a897Sspz */
997673729aSmrg#define LENGTHOF(r)	(SIZEOF(r) >> 2)
1009d21a897Sspz
1019d21a897Sspz/* Somewhat arbitrary limit on maximum reply size we'll try to read. */
1027673729aSmrg#define MAX_REPLY_LENGTH	((64 * 1024 * 1024) >> 2)
1039d21a897Sspz
10423a0898aSmrgextern void ErrorF(const char *f, ...);
10523a0898aSmrg
10623a0898aSmrgstatic int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
10723a0898aSmrgstatic int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
10841c30155Smrgstatic int fs_read_list_info ( FontPathElementPtr fpe,
10923a0898aSmrg			       FSBlockDataPtr blockrec );
11023a0898aSmrg
11123a0898aSmrgextern fd_set _fs_fd_mask;
11223a0898aSmrg
11341c30155Smrgstatic void fs_block_handler ( pointer data, OSTimePtr wt,
11423a0898aSmrg			       pointer LastSelectMask );
11523a0898aSmrgstatic int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
11623a0898aSmrg
11723a0898aSmrg/*
11841c30155Smrg * List of all FPEs
11923a0898aSmrg */
12023a0898aSmrgstatic FSFpePtr fs_fpes;
12123a0898aSmrg/*
12223a0898aSmrg * Union of all FPE blockStates
12323a0898aSmrg */
12423a0898aSmrgstatic CARD32	fs_blockState;
12523a0898aSmrg
12623a0898aSmrgstatic int _fs_restart_connection ( FSFpePtr conn );
12741c30155Smrgstatic void fs_send_query_bitmaps ( FontPathElementPtr fpe,
12823a0898aSmrg				   FSBlockDataPtr blockrec );
12923a0898aSmrgstatic int fs_send_close_font ( FontPathElementPtr fpe, Font id );
13023a0898aSmrgstatic void fs_client_died ( pointer client, FontPathElementPtr fpe );
13123a0898aSmrgstatic void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
13223a0898aSmrgstatic void _fs_client_resolution ( FSFpePtr conn );
13323a0898aSmrgstatic fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
13423a0898aSmrgstatic int fs_await_reply (FSFpePtr conn);
13523a0898aSmrgstatic void _fs_do_blocked (FSFpePtr conn);
13623a0898aSmrgstatic void fs_cleanup_bfont (FSBlockedFontPtr bfont);
13723a0898aSmrg
13823a0898aSmrgchar _fs_glyph_undefined;
13923a0898aSmrgchar _fs_glyph_requested;
14023a0898aSmrgstatic char _fs_glyph_zero_length;
14123a0898aSmrg
14223a0898aSmrgstatic int  generationCount;
14323a0898aSmrg
14423a0898aSmrgstatic int FontServerRequestTimeout = 30 * 1000;
14523a0898aSmrg
14623a0898aSmrgstatic void
14723a0898aSmrg_fs_close_server (FSFpePtr conn);
14823a0898aSmrg
14923a0898aSmrgstatic FSFpePtr
15023a0898aSmrg_fs_init_conn (char *servername);
15123a0898aSmrg
15223a0898aSmrgstatic int
15323a0898aSmrg_fs_wait_connect (FSFpePtr conn);
15423a0898aSmrg
15523a0898aSmrgstatic int
15623a0898aSmrg_fs_send_init_packets (FSFpePtr conn);
15723a0898aSmrg
15823a0898aSmrgstatic void
15923a0898aSmrg_fs_check_reconnect (FSFpePtr conn);
16023a0898aSmrg
16123a0898aSmrgstatic void
16223a0898aSmrg_fs_start_reconnect (FSFpePtr conn);
16323a0898aSmrg
16423a0898aSmrgstatic void
16523a0898aSmrg_fs_free_conn (FSFpePtr conn);
16623a0898aSmrg
16723a0898aSmrgstatic int
16823a0898aSmrgfs_free_fpe(FontPathElementPtr fpe);
16923a0898aSmrg
17023a0898aSmrg/*
17123a0898aSmrg * Font server access
17223a0898aSmrg *
17323a0898aSmrg * the basic idea for the non-blocking access is to have the function
17423a0898aSmrg * called multiple times until the actual data is returned, instead
17523a0898aSmrg * of ClientBlocked.
17623a0898aSmrg *
17723a0898aSmrg * the first call to the function will cause the request to be sent to
17823a0898aSmrg * the font server, and a block record to be stored in the fpe's list
17923a0898aSmrg * of outstanding requests.  the FS block handler also sticks the
18023a0898aSmrg * proper set of fd's into the select mask.  when data is ready to be
18123a0898aSmrg * read in, the FS wakup handler will be hit.  this will read the
18223a0898aSmrg * data off the wire into the proper block record, and then signal the
18323a0898aSmrg * client that caused the block so that it can restart.  it will then
18423a0898aSmrg * call the access function again, which will realize that the data has
18523a0898aSmrg * arrived and return it.
18623a0898aSmrg */
18723a0898aSmrg
18823a0898aSmrg
18923a0898aSmrg#ifdef DEBUG
19023a0898aSmrgstatic void
19123a0898aSmrg_fs_add_req_log(FSFpePtr conn, int opcode)
19223a0898aSmrg{
19323a0898aSmrg    conn->current_seq++;
19423a0898aSmrg    fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
19523a0898aSmrg	     conn->current_seq, opcode);
19623a0898aSmrg    conn->reqbuffer[conn->reqindex].opcode = opcode;
19723a0898aSmrg    conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
19823a0898aSmrg    conn->reqindex++;
19923a0898aSmrg    if (conn->reqindex == REQUEST_LOG_SIZE)
20023a0898aSmrg	conn->reqindex = 0;
20123a0898aSmrg}
20223a0898aSmrg
20323a0898aSmrgstatic void
20423a0898aSmrg_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
20523a0898aSmrg{
20623a0898aSmrg    int	    i;
20723a0898aSmrg
20823a0898aSmrg    for (i = 0; i < REQUEST_LOG_SIZE; i++)
20923a0898aSmrg	if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
21023a0898aSmrg	    break;
21123a0898aSmrg    if (i == REQUEST_LOG_SIZE)
21223a0898aSmrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: unknown\n",
21323a0898aSmrg		 rep->sequenceNumber);
21423a0898aSmrg    else
21523a0898aSmrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: %d\n",
21623a0898aSmrg		 rep->sequenceNumber,
21723a0898aSmrg		 conn->reqbuffer[i].opcode);
21823a0898aSmrg}
2199d21a897Sspz
2209d21a897Sspz#define _fs_reply_failed(rep, name, op) do {                            \
2219d21a897Sspz    if (rep) {                                                          \
2229d21a897Sspz        if (rep->type == FS_Error)                                      \
2239d21a897Sspz            fprintf (stderr, "Error: %d Request: %s\n",                 \
2249d21a897Sspz                     ((fsError *)rep)->request, #name);                 \
2259d21a897Sspz        else                                                            \
2269d21a897Sspz            fprintf (stderr, "Bad Length for %s Reply: %d %s %d\n",     \
2279d21a897Sspz                     #name, rep->length, op, LENGTHOF(name));           \
2289d21a897Sspz    }                                                                   \
2299d21a897Sspz} while (0)
2309d21a897Sspz
23123a0898aSmrg#else
23223a0898aSmrg#define _fs_add_req_log(conn,op)    ((conn)->current_seq++)
23323a0898aSmrg#define _fs_add_rep_log(conn,rep)
2349d21a897Sspz#define _fs_reply_failed(rep,name,op)
23523a0898aSmrg#endif
23623a0898aSmrg
23723a0898aSmrgstatic Bool
23823a0898aSmrgfs_name_check(char *name)
23923a0898aSmrg{
24023a0898aSmrg    /* Just make sure there is a protocol/ prefix */
24123a0898aSmrg    return (name && *name != '/' && strchr(name, '/'));
24223a0898aSmrg}
24323a0898aSmrg
24423a0898aSmrgstatic void
24523a0898aSmrg_fs_client_resolution(FSFpePtr conn)
24623a0898aSmrg{
24723a0898aSmrg    fsSetResolutionReq srreq;
24823a0898aSmrg    int         num_res;
24923a0898aSmrg    FontResolutionPtr res;
25023a0898aSmrg
25123a0898aSmrg    res = GetClientResolutions(&num_res);
25223a0898aSmrg
25323a0898aSmrg    if (num_res) {
25423a0898aSmrg	srreq.reqType = FS_SetResolution;
25523a0898aSmrg	srreq.num_resolutions = num_res;
25623a0898aSmrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
25723a0898aSmrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
25823a0898aSmrg
25923a0898aSmrg	_fs_add_req_log(conn, FS_SetResolution);
26023a0898aSmrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
26123a0898aSmrg	    (void)_fs_write_pad(conn, (char *) res,
26223a0898aSmrg				(num_res * SIZEOF(fsResolution)));
26323a0898aSmrg    }
26423a0898aSmrg}
26523a0898aSmrg
26641c30155Smrg/*
26723a0898aSmrg * close font server and remove any state associated with
26823a0898aSmrg * this connection - this includes any client records.
26923a0898aSmrg */
27023a0898aSmrg
27123a0898aSmrgstatic void
27223a0898aSmrgfs_close_conn(FSFpePtr conn)
27323a0898aSmrg{
27423a0898aSmrg    FSClientPtr	client, nclient;
27523a0898aSmrg
27623a0898aSmrg    _fs_close_server (conn);
27741c30155Smrg
27841c30155Smrg    for (client = conn->clients; client; client = nclient)
27923a0898aSmrg    {
28023a0898aSmrg	nclient = client->next;
2817f7f5e4eSmrg	free (client);
28223a0898aSmrg    }
28323a0898aSmrg    conn->clients = NULL;
28423a0898aSmrg}
28523a0898aSmrg
28623a0898aSmrg/*
28723a0898aSmrg * the wakeup handlers have to be set when the FPE is open, and not
28823a0898aSmrg * removed until it is freed, in order to handle unexpected data, like
28923a0898aSmrg * events
29023a0898aSmrg */
29123a0898aSmrg/* ARGSUSED */
29223a0898aSmrgstatic int
29323a0898aSmrgfs_init_fpe(FontPathElementPtr fpe)
29423a0898aSmrg{
29523a0898aSmrg    FSFpePtr    conn;
29623a0898aSmrg    char       *name;
29723a0898aSmrg    int         err;
29823a0898aSmrg    int		ret;
29923a0898aSmrg
30023a0898aSmrg    /* open font server */
30123a0898aSmrg    /* create FS specific fpe info */
30223a0898aSmrg    name = fpe->name;
30323a0898aSmrg
30423a0898aSmrg    /* hack for old style names */
30523a0898aSmrg    if (*name == ':')
30623a0898aSmrg	name++;			/* skip ':' */
30723a0898aSmrg
30823a0898aSmrg    conn = _fs_init_conn (name);
30923a0898aSmrg    if (!conn)
31023a0898aSmrg	err = AllocError;
31123a0898aSmrg    else
31223a0898aSmrg    {
31323a0898aSmrg	err = init_fs_handlers (fpe, fs_block_handler);
31423a0898aSmrg	if (err != Successful)
31523a0898aSmrg	{
31623a0898aSmrg	    _fs_free_conn (conn);
31723a0898aSmrg	    err = AllocError;
31823a0898aSmrg	}
31923a0898aSmrg	else
32023a0898aSmrg	{
32123a0898aSmrg	    fpe->private = conn;
32223a0898aSmrg	    conn->next = fs_fpes;
32323a0898aSmrg	    fs_fpes = conn;
32423a0898aSmrg	    ret = _fs_wait_connect (conn);
32523a0898aSmrg	    if (ret != FSIO_READY)
32623a0898aSmrg	    {
32723a0898aSmrg		fs_free_fpe (fpe);
32823a0898aSmrg		err = BadFontPath;
32923a0898aSmrg	    }
33023a0898aSmrg	    else
33123a0898aSmrg		err = Successful;
33223a0898aSmrg	}
33323a0898aSmrg    }
33441c30155Smrg
33523a0898aSmrg    if (err == Successful)
33623a0898aSmrg    {
33723a0898aSmrg#ifdef NCD
33823a0898aSmrg	if (configData.ExtendedFontDiags)
33923a0898aSmrg	    printf("Connected to font server \"%s\"\n", name);
34023a0898aSmrg#endif
34123a0898aSmrg#ifdef DEBUG
34223a0898aSmrg	fprintf (stderr, "connected to FS \"%s\"\n", name);
34323a0898aSmrg#endif
34423a0898aSmrg    }
34523a0898aSmrg    else
34623a0898aSmrg    {
34723a0898aSmrg#ifdef DEBUG
34823a0898aSmrg	fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
34923a0898aSmrg#endif
35023a0898aSmrg#ifdef NCD
35123a0898aSmrg	if (configData.ExtendedFontDiags)
35223a0898aSmrg	    printf("Failed to connect to font server \"%s\"\n", name);
35323a0898aSmrg#endif
35423a0898aSmrg	;
35523a0898aSmrg    }
35623a0898aSmrg    return err;
35723a0898aSmrg}
35823a0898aSmrg
35923a0898aSmrgstatic int
36023a0898aSmrgfs_reset_fpe(FontPathElementPtr fpe)
36123a0898aSmrg{
36223a0898aSmrg    (void) _fs_send_init_packets((FSFpePtr) fpe->private);
36323a0898aSmrg    return Successful;
36423a0898aSmrg}
36523a0898aSmrg
36623a0898aSmrg/*
36723a0898aSmrg * this shouldn't be called till all refs to the FPE are gone
36823a0898aSmrg */
36923a0898aSmrg
37023a0898aSmrgstatic int
37123a0898aSmrgfs_free_fpe(FontPathElementPtr fpe)
37223a0898aSmrg{
37323a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private, *prev;
37441c30155Smrg
37523a0898aSmrg    /* unhook from chain of all font servers */
37623a0898aSmrg    for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
37723a0898aSmrg    {
37823a0898aSmrg	if (*prev == conn)
37923a0898aSmrg	{
38023a0898aSmrg	    *prev = conn->next;
38123a0898aSmrg	    break;
38223a0898aSmrg	}
38323a0898aSmrg    }
38423a0898aSmrg    _fs_unmark_block (conn, conn->blockState);
38523a0898aSmrg    fs_close_conn(conn);
38623a0898aSmrg    remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
38723a0898aSmrg    _fs_free_conn (conn);
38823a0898aSmrg    fpe->private = (pointer) 0;
38923a0898aSmrg
39023a0898aSmrg#ifdef NCD
39123a0898aSmrg    if (configData.ExtendedFontDiags)
39223a0898aSmrg	printf("Disconnected from font server \"%s\"\n", fpe->name);
39323a0898aSmrg#endif
39423a0898aSmrg#ifdef DEBUG
39523a0898aSmrg    fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
39623a0898aSmrg#endif
39723a0898aSmrg
39823a0898aSmrg    return Successful;
39923a0898aSmrg}
40023a0898aSmrg
40123a0898aSmrgstatic      FSBlockDataPtr
40223a0898aSmrgfs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
40323a0898aSmrg{
40423a0898aSmrg    FSBlockDataPtr blockrec,
40523a0898aSmrg                *prev;
40623a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
40723a0898aSmrg    int         size;
40823a0898aSmrg
40923a0898aSmrg    switch (type) {
41023a0898aSmrg    case FS_OPEN_FONT:
41123a0898aSmrg	size = sizeof(FSBlockedFontRec);
41223a0898aSmrg	break;
41323a0898aSmrg    case FS_LOAD_GLYPHS:
41423a0898aSmrg	size = sizeof(FSBlockedGlyphRec);
41523a0898aSmrg	break;
41623a0898aSmrg    case FS_LIST_FONTS:
41723a0898aSmrg	size = sizeof(FSBlockedListRec);
41823a0898aSmrg	break;
41923a0898aSmrg    case FS_LIST_WITH_INFO:
42023a0898aSmrg	size = sizeof(FSBlockedListInfoRec);
42123a0898aSmrg	break;
42223a0898aSmrg    default:
42323a0898aSmrg	size = 0;
42423a0898aSmrg	break;
42523a0898aSmrg    }
4267f7f5e4eSmrg    blockrec = malloc(sizeof(FSBlockDataRec) + size);
42723a0898aSmrg    if (!blockrec)
42823a0898aSmrg	return (FSBlockDataPtr) 0;
42923a0898aSmrg    blockrec->data = (pointer) (blockrec + 1);
43023a0898aSmrg    blockrec->client = client;
43123a0898aSmrg    blockrec->sequenceNumber = -1;
43223a0898aSmrg    blockrec->errcode = StillWorking;
43323a0898aSmrg    blockrec->type = type;
43423a0898aSmrg    blockrec->depending = 0;
43523a0898aSmrg    blockrec->next = (FSBlockDataPtr) 0;
43641c30155Smrg
43723a0898aSmrg    /* stick it on the end of the list (since its expected last) */
43823a0898aSmrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
43923a0898aSmrg	;
44023a0898aSmrg    *prev = blockrec;
44123a0898aSmrg
44223a0898aSmrg    return blockrec;
44323a0898aSmrg}
44423a0898aSmrg
44523a0898aSmrgstatic void
44623a0898aSmrg_fs_set_pending_reply (FSFpePtr conn)
44723a0898aSmrg{
44823a0898aSmrg    FSBlockDataPtr  blockrec;
44941c30155Smrg
45023a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
45123a0898aSmrg	if (blockrec->errcode == StillWorking)
45223a0898aSmrg	    break;
45323a0898aSmrg    if (blockrec)
45423a0898aSmrg    {
45523a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
45623a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
45723a0898aSmrg    }
45823a0898aSmrg    else
45923a0898aSmrg	_fs_unmark_block (conn, FS_PENDING_REPLY);
46023a0898aSmrg}
46123a0898aSmrg
46223a0898aSmrgstatic void
46323a0898aSmrg_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
46423a0898aSmrg{
46523a0898aSmrg    FSBlockDataPtr *prev;
46623a0898aSmrg
46723a0898aSmrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
46841c30155Smrg	if (*prev == blockrec)
46923a0898aSmrg	{
47023a0898aSmrg	    *prev = blockrec->next;
47123a0898aSmrg	    break;
47223a0898aSmrg	}
47323a0898aSmrg    if (blockrec->type == FS_LOAD_GLYPHS)
47423a0898aSmrg    {
47523a0898aSmrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
47623a0898aSmrg	if (bglyph->num_expected_ranges)
4777f7f5e4eSmrg	    free(bglyph->expected_ranges);
47823a0898aSmrg    }
4797f7f5e4eSmrg    free(blockrec);
48023a0898aSmrg    _fs_set_pending_reply (conn);
48123a0898aSmrg}
48223a0898aSmrg
48323a0898aSmrgstatic void
48423a0898aSmrg_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
48523a0898aSmrg{
48623a0898aSmrg    FSClientsDependingPtr p;
48741c30155Smrg
48823a0898aSmrg    while ((p = *clients_depending))
48923a0898aSmrg    {
49023a0898aSmrg	*clients_depending = p->next;
49123a0898aSmrg	ClientSignal(p->client);
4927f7f5e4eSmrg	free(p);
49323a0898aSmrg    }
49423a0898aSmrg}
49523a0898aSmrg
49623a0898aSmrgstatic int
49723a0898aSmrg_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
49823a0898aSmrg{
49923a0898aSmrg    FSClientsDependingPtr   new, cd;
50041c30155Smrg
50141c30155Smrg    for (; (cd = *clients_depending);
50223a0898aSmrg	 clients_depending = &(*clients_depending)->next)
50323a0898aSmrg    {
50441c30155Smrg	if (cd->client == client)
50523a0898aSmrg	    return Suspended;
50623a0898aSmrg    }
50741c30155Smrg
5087f7f5e4eSmrg    new = malloc (sizeof (FSClientsDependingRec));
50923a0898aSmrg    if (!new)
51023a0898aSmrg	return BadAlloc;
51123a0898aSmrg
51223a0898aSmrg    new->client = client;
51323a0898aSmrg    new->next = 0;
51423a0898aSmrg    *clients_depending = new;
51523a0898aSmrg    return Suspended;
51623a0898aSmrg}
51723a0898aSmrg
51823a0898aSmrg/*
51923a0898aSmrg * When a request is aborted due to a font server failure,
52023a0898aSmrg * signal any depending clients to restart their dependant
52123a0898aSmrg * requests
52223a0898aSmrg */
52323a0898aSmrgstatic void
52423a0898aSmrg_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
52523a0898aSmrg{
52623a0898aSmrg    switch(blockrec->type) {
52723a0898aSmrg    case FS_OPEN_FONT: {
52823a0898aSmrg	FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
52941c30155Smrg
53023a0898aSmrg	fs_cleanup_bfont (bfont);
53123a0898aSmrg	_fs_signal_clients_depending(&bfont->clients_depending);
53223a0898aSmrg	break;
53323a0898aSmrg    }
53423a0898aSmrg    case FS_LOAD_GLYPHS: {
53523a0898aSmrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
53641c30155Smrg
53723a0898aSmrg	_fs_clean_aborted_loadglyphs(bglyph->pfont,
53823a0898aSmrg				     bglyph->num_expected_ranges,
53941c30155Smrg				     bglyph->expected_ranges);
54023a0898aSmrg	_fs_signal_clients_depending(&bglyph->clients_depending);
54123a0898aSmrg	break;
54223a0898aSmrg    }
54323a0898aSmrg    case FS_LIST_FONTS:
54423a0898aSmrg	break;
54523a0898aSmrg    case FS_LIST_WITH_INFO: {
54623a0898aSmrg	FSBlockedListInfoPtr binfo;
54723a0898aSmrg	binfo = (FSBlockedListInfoPtr) blockrec->data;
54823a0898aSmrg	if (binfo->status == FS_LFWI_REPLY)
54923a0898aSmrg	    FD_SET(conn->fs_fd, &_fs_fd_mask);
55023a0898aSmrg	_fs_free_props (&binfo->info);
55123a0898aSmrg    }
55223a0898aSmrg    default:
55323a0898aSmrg	break;
55423a0898aSmrg    }
55523a0898aSmrg}
55623a0898aSmrg
55723a0898aSmrgstatic void
55823a0898aSmrgfs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
55923a0898aSmrg{
56023a0898aSmrg    _fs_clean_aborted_blockrec (conn, blockrec);
56123a0898aSmrg    _fs_remove_block_rec (conn, blockrec);
56223a0898aSmrg}
56323a0898aSmrg
56423a0898aSmrg/*
56523a0898aSmrg * Tell the font server we've failed to complete an open and
56623a0898aSmrg * then unload the partially created font
56723a0898aSmrg */
56823a0898aSmrgstatic void
56923a0898aSmrgfs_cleanup_bfont (FSBlockedFontPtr bfont)
57023a0898aSmrg{
57123a0898aSmrg    FSFontDataRec *fsd;
57223a0898aSmrg
57323a0898aSmrg    if (bfont->pfont)
57423a0898aSmrg    {
57523a0898aSmrg	fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
57641c30155Smrg
57723a0898aSmrg	/* make sure the FS knows we choked on it */
57823a0898aSmrg	fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
57941c30155Smrg
58023a0898aSmrg	/*
58141c30155Smrg	 * Either unload the font if it's being opened for
58223a0898aSmrg	 * the first time, or smash the generation field to
58323a0898aSmrg	 * mark this font as an orphan
58423a0898aSmrg	 */
58523a0898aSmrg	if (!(bfont->flags & FontReopen))
58623a0898aSmrg	{
58723a0898aSmrg	    if (bfont->freeFont)
58823a0898aSmrg		(*bfont->pfont->unload_font) (bfont->pfont);
58923a0898aSmrg#ifdef DEBUG
59023a0898aSmrg	    else
59123a0898aSmrg		fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
59223a0898aSmrg#endif
59323a0898aSmrg	    bfont->pfont = 0;
59423a0898aSmrg	}
59523a0898aSmrg	else
59623a0898aSmrg	    fsd->generation = -1;
59723a0898aSmrg    }
59823a0898aSmrg}
59923a0898aSmrg
60023a0898aSmrg/*
60123a0898aSmrg * Check to see if a complete reply is waiting
60223a0898aSmrg */
60323a0898aSmrgstatic fsGenericReply *
60423a0898aSmrgfs_get_reply (FSFpePtr conn, int *error)
60523a0898aSmrg{
60623a0898aSmrg    char	    *buf;
60723a0898aSmrg    fsGenericReply  *rep;
60823a0898aSmrg    int		    ret;
60923a0898aSmrg
61023a0898aSmrg    /* block if the connection is down or paused in lfwi */
61123a0898aSmrg    if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
61223a0898aSmrg    {
61323a0898aSmrg	*error = FSIO_BLOCK;
61423a0898aSmrg	return 0;
61523a0898aSmrg    }
61641c30155Smrg
61723a0898aSmrg    ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
61823a0898aSmrg    if (ret != FSIO_READY)
61923a0898aSmrg    {
62023a0898aSmrg	*error = FSIO_BLOCK;
62123a0898aSmrg	return 0;
62223a0898aSmrg    }
62341c30155Smrg
62423a0898aSmrg    rep = (fsGenericReply *) buf;
62523a0898aSmrg
6269d21a897Sspz    /*
6279d21a897Sspz     * Refuse to accept replies longer than a maximum reasonable length,
6289d21a897Sspz     * before we pass to _fs_start_read, since it will try to resize the
6299d21a897Sspz     * incoming connection buffer to this size.  Also avoids integer overflow
6309d21a897Sspz     * on 32-bit systems.
6319d21a897Sspz     */
6329d21a897Sspz    if (rep->length > MAX_REPLY_LENGTH)
6339d21a897Sspz    {
6347673729aSmrg	ErrorF("fserve: reply length %d > MAX_REPLY_LENGTH, disconnecting"
6357673729aSmrg	       " from font server\n", rep->length);
6367673729aSmrg	_fs_connection_died (conn);
6377673729aSmrg	*error = FSIO_ERROR;
6387673729aSmrg	return 0;
6399d21a897Sspz    }
6409d21a897Sspz
64123a0898aSmrg    ret = _fs_start_read (conn, rep->length << 2, &buf);
64223a0898aSmrg    if (ret != FSIO_READY)
64323a0898aSmrg    {
64423a0898aSmrg	*error = FSIO_BLOCK;
64523a0898aSmrg	return 0;
64623a0898aSmrg    }
64723a0898aSmrg
64823a0898aSmrg    *error = FSIO_READY;
64941c30155Smrg
65023a0898aSmrg    return (fsGenericReply *) buf;
65123a0898aSmrg}
65223a0898aSmrg
65323a0898aSmrgstatic Bool
65423a0898aSmrgfs_reply_ready (FSFpePtr conn)
65523a0898aSmrg{
65623a0898aSmrg    fsGenericReply  *rep;
65741c30155Smrg
65823a0898aSmrg    if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
65923a0898aSmrg	return FALSE;
66023a0898aSmrg    if (fs_data_read (conn) < sizeof (fsGenericReply))
66123a0898aSmrg	return FALSE;
66223a0898aSmrg    rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
66323a0898aSmrg    if (fs_data_read (conn) < rep->length << 2)
66423a0898aSmrg	return FALSE;
66523a0898aSmrg    return TRUE;
66623a0898aSmrg}
66723a0898aSmrg
66823a0898aSmrgstatic void
66923a0898aSmrg_fs_pending_reply (FSFpePtr conn)
67023a0898aSmrg{
67123a0898aSmrg    if (!(conn->blockState & FS_PENDING_REPLY))
67223a0898aSmrg    {
67323a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
67423a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
67523a0898aSmrg    }
67623a0898aSmrg}
67723a0898aSmrg
67823a0898aSmrgstatic void
67923a0898aSmrg_fs_prepare_for_reply (FSFpePtr conn)
68023a0898aSmrg{
68123a0898aSmrg    _fs_pending_reply (conn);
68223a0898aSmrg    _fs_flush (conn);
68323a0898aSmrg}
68423a0898aSmrg
68523a0898aSmrg/*
68623a0898aSmrg * Block (for a while) awaiting a complete reply
68723a0898aSmrg */
68823a0898aSmrgstatic int
68923a0898aSmrgfs_await_reply (FSFpePtr conn)
69023a0898aSmrg{
69123a0898aSmrg    int		    ret;
69241c30155Smrg
69323a0898aSmrg    if (conn->blockState & FS_COMPLETE_REPLY)
69423a0898aSmrg	return FSIO_READY;
69541c30155Smrg
69623a0898aSmrg    while (!fs_get_reply (conn, &ret))
69723a0898aSmrg    {
69823a0898aSmrg	if (ret != FSIO_BLOCK)
69923a0898aSmrg	    return ret;
70023a0898aSmrg	if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
70123a0898aSmrg	{
70223a0898aSmrg	    _fs_connection_died (conn);
70323a0898aSmrg	    return FSIO_ERROR;
70423a0898aSmrg	}
70523a0898aSmrg    }
70623a0898aSmrg    return FSIO_READY;
70723a0898aSmrg}
70823a0898aSmrg
70923a0898aSmrg/*
71023a0898aSmrg * Process the reply to an OpenBitmapFont request
71123a0898aSmrg */
71223a0898aSmrgstatic int
71323a0898aSmrgfs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
71423a0898aSmrg{
71523a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
71623a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
71723a0898aSmrg    fsOpenBitmapFontReply   *rep;
71823a0898aSmrg    FSBlockDataPtr	    blockOrig;
71923a0898aSmrg    FSBlockedFontPtr	    origBfont;
72023a0898aSmrg    int			    ret;
72123a0898aSmrg
72223a0898aSmrg    rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
7239d21a897Sspz    if (!rep || rep->type == FS_Error ||
7247673729aSmrg	(rep->length != LENGTHOF(fsOpenBitmapFontReply)))
72523a0898aSmrg    {
72623a0898aSmrg	if (ret == FSIO_BLOCK)
72723a0898aSmrg	    return StillWorking;
72823a0898aSmrg	if (rep)
72923a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
73023a0898aSmrg	fs_cleanup_bfont (bfont);
7317673729aSmrg	_fs_reply_failed (rep, fsOpenBitmapFontReply, "!=");
73223a0898aSmrg	return BadFontName;
73323a0898aSmrg    }
73441c30155Smrg
73523a0898aSmrg    /* If we're not reopening a font and FS detected a duplicate font
73623a0898aSmrg       open request, replace our reference to the new font with a
73723a0898aSmrg       reference to an existing font (possibly one not finished
73823a0898aSmrg       opening).  If this is a reopen, keep the new font reference...
73923a0898aSmrg       it's got the metrics and extents we read when the font was opened
74023a0898aSmrg       before.  This also gives us the freedom to easily close the font
74123a0898aSmrg       if we we decide (in fs_read_query_info()) that we don't like what
74223a0898aSmrg       we got. */
74323a0898aSmrg
74441c30155Smrg    if (rep->otherid && !(bfont->flags & FontReopen))
74523a0898aSmrg    {
74623a0898aSmrg	fs_cleanup_bfont (bfont);
74741c30155Smrg
74823a0898aSmrg	/* Find old font if we're completely done getting it from server. */
74923a0898aSmrg	bfont->pfont = find_old_font(rep->otherid);
75023a0898aSmrg	bfont->freeFont = FALSE;
75123a0898aSmrg	bfont->fontid = rep->otherid;
75223a0898aSmrg	bfont->state = FS_DONE_REPLY;
75323a0898aSmrg	/*
75423a0898aSmrg	 * look for a blocked request to open the same font
75523a0898aSmrg	 */
75623a0898aSmrg	for (blockOrig = conn->blockedRequests;
75723a0898aSmrg		blockOrig;
75841c30155Smrg		blockOrig = blockOrig->next)
75923a0898aSmrg	{
76041c30155Smrg	    if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
76123a0898aSmrg	    {
76223a0898aSmrg		origBfont = (FSBlockedFontPtr) blockOrig->data;
76341c30155Smrg		if (origBfont->fontid == rep->otherid)
76423a0898aSmrg		{
76523a0898aSmrg		    blockrec->depending = blockOrig->depending;
76623a0898aSmrg		    blockOrig->depending = blockrec;
76723a0898aSmrg		    bfont->state = FS_DEPENDING;
76823a0898aSmrg		    bfont->pfont = origBfont->pfont;
76923a0898aSmrg		    break;
77023a0898aSmrg		}
77123a0898aSmrg	    }
77223a0898aSmrg	}
77323a0898aSmrg	if (bfont->pfont == NULL)
77423a0898aSmrg	{
77523a0898aSmrg	    /* XXX - something nasty happened */
77623a0898aSmrg	    ret = BadFontName;
77723a0898aSmrg	}
77823a0898aSmrg	else
77923a0898aSmrg	    ret = AccessDone;
78023a0898aSmrg    }
78123a0898aSmrg    else
78223a0898aSmrg    {
78323a0898aSmrg	bfont->pfont->info.cachable = rep->cachable != 0;
78423a0898aSmrg	bfont->state = FS_INFO_REPLY;
78523a0898aSmrg	/*
78623a0898aSmrg	 * Reset the blockrec for the next reply
78723a0898aSmrg	 */
78823a0898aSmrg	blockrec->sequenceNumber = bfont->queryInfoSequence;
78923a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
79023a0898aSmrg	ret = StillWorking;
79123a0898aSmrg    }
79223a0898aSmrg    _fs_done_read (conn, rep->length << 2);
79323a0898aSmrg    return ret;
79423a0898aSmrg}
79523a0898aSmrg
79623a0898aSmrgstatic Bool
79723a0898aSmrgfs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
79823a0898aSmrg{
79923a0898aSmrg    int	    i;
80041c30155Smrg
80123a0898aSmrg    if (pInfo1->firstCol != pInfo2->firstCol ||
80223a0898aSmrg	pInfo1->lastCol != pInfo2->lastCol ||
80323a0898aSmrg	pInfo1->firstRow != pInfo2->firstRow ||
80423a0898aSmrg	pInfo1->lastRow != pInfo2->lastRow ||
80523a0898aSmrg	pInfo1->defaultCh != pInfo2->defaultCh ||
80623a0898aSmrg	pInfo1->noOverlap != pInfo2->noOverlap ||
80723a0898aSmrg	pInfo1->terminalFont != pInfo2->terminalFont ||
80823a0898aSmrg	pInfo1->constantMetrics != pInfo2->constantMetrics ||
80923a0898aSmrg	pInfo1->constantWidth != pInfo2->constantWidth ||
81023a0898aSmrg	pInfo1->inkInside != pInfo2->inkInside ||
81123a0898aSmrg	pInfo1->inkMetrics != pInfo2->inkMetrics ||
81223a0898aSmrg	pInfo1->allExist != pInfo2->allExist ||
81323a0898aSmrg	pInfo1->drawDirection != pInfo2->drawDirection ||
81423a0898aSmrg	pInfo1->cachable != pInfo2->cachable ||
81523a0898aSmrg	pInfo1->anamorphic != pInfo2->anamorphic ||
81623a0898aSmrg	pInfo1->maxOverlap != pInfo2->maxOverlap ||
81723a0898aSmrg	pInfo1->fontAscent != pInfo2->fontAscent ||
81823a0898aSmrg	pInfo1->fontDescent != pInfo2->fontDescent ||
81923a0898aSmrg	pInfo1->nprops != pInfo2->nprops)
82023a0898aSmrg	return FALSE;
82123a0898aSmrg
82223a0898aSmrg#define MATCH(xci1, xci2) \
82323a0898aSmrg    (((xci1).leftSideBearing == (xci2).leftSideBearing) && \
82423a0898aSmrg     ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
82523a0898aSmrg     ((xci1).characterWidth == (xci2).characterWidth) && \
82623a0898aSmrg     ((xci1).ascent == (xci2).ascent) && \
82723a0898aSmrg     ((xci1).descent == (xci2).descent) && \
82823a0898aSmrg     ((xci1).attributes == (xci2).attributes))
82923a0898aSmrg
83023a0898aSmrg    if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
83123a0898aSmrg	!MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
83223a0898aSmrg	!MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
83323a0898aSmrg	!MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
83423a0898aSmrg	return FALSE;
83523a0898aSmrg
83623a0898aSmrg#undef MATCH
83723a0898aSmrg
83823a0898aSmrg    for (i = 0; i < pInfo1->nprops; i++)
83923a0898aSmrg	if (pInfo1->isStringProp[i] !=
84023a0898aSmrg		pInfo2->isStringProp[i] ||
84123a0898aSmrg	    pInfo1->props[i].name !=
84223a0898aSmrg		pInfo2->props[i].name ||
84323a0898aSmrg	    pInfo1->props[i].value !=
84423a0898aSmrg		pInfo2->props[i].value)
84523a0898aSmrg	{
84623a0898aSmrg	    return FALSE;
84723a0898aSmrg	}
84823a0898aSmrg    return TRUE;
84923a0898aSmrg}
85023a0898aSmrg
85123a0898aSmrgstatic int
85223a0898aSmrgfs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
85323a0898aSmrg{
85423a0898aSmrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
85523a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
85623a0898aSmrg    fsQueryXInfoReply	*rep;
85723a0898aSmrg    char		*buf;
8587673729aSmrg    long		bufleft; /* length of reply left to use */
85923a0898aSmrg    fsPropInfo		*pi;
86023a0898aSmrg    fsPropOffset	*po;
86123a0898aSmrg    pointer		pd;
86223a0898aSmrg    FontInfoPtr		pInfo;
86323a0898aSmrg    FontInfoRec		tempInfo;
86423a0898aSmrg    int			err;
86523a0898aSmrg    int			ret;
86623a0898aSmrg
86723a0898aSmrg    rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
8689d21a897Sspz    if (!rep || rep->type == FS_Error ||
8697673729aSmrg	(rep->length < LENGTHOF(fsQueryXInfoReply)))
87023a0898aSmrg    {
87123a0898aSmrg	if (ret == FSIO_BLOCK)
87223a0898aSmrg	    return StillWorking;
87323a0898aSmrg	if (rep)
87423a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
87523a0898aSmrg	fs_cleanup_bfont (bfont);
8767673729aSmrg	_fs_reply_failed (rep, fsQueryXInfoReply, "<");
87723a0898aSmrg	return BadFontName;
87823a0898aSmrg    }
87941c30155Smrg
88023a0898aSmrg    /* If this is a reopen, accumulate the query info into a dummy
88123a0898aSmrg       font and compare to our original data. */
88223a0898aSmrg    if (bfont->flags & FontReopen)
88323a0898aSmrg	pInfo = &tempInfo;
88423a0898aSmrg    else
88523a0898aSmrg	pInfo = &bfont->pfont->info;
88623a0898aSmrg
88723a0898aSmrg    buf = (char *) rep;
88823a0898aSmrg    buf += SIZEOF(fsQueryXInfoReply);
88941c30155Smrg
8909d21a897Sspz    bufleft = rep->length << 2;
8919d21a897Sspz    bufleft -= SIZEOF(fsQueryXInfoReply);
8929d21a897Sspz
89323a0898aSmrg    /* move the data over */
89423a0898aSmrg    fsUnpack_XFontInfoHeader(rep, pInfo);
89541c30155Smrg
89623a0898aSmrg    /* compute accelerators */
89723a0898aSmrg    _fs_init_fontinfo(conn, pInfo);
89823a0898aSmrg
89923a0898aSmrg    /* Compute offsets into the reply */
9009d21a897Sspz    if (bufleft < SIZEOF(fsPropInfo))
9019d21a897Sspz    {
9027673729aSmrg	ret = -1;
9039d21a897Sspz#ifdef DEBUG
9047673729aSmrg	fprintf(stderr, "fsQueryXInfo: bufleft (%ld) < SIZEOF(fsPropInfo)\n",
9057673729aSmrg		bufleft);
9069d21a897Sspz#endif
9077673729aSmrg	goto bail;
9089d21a897Sspz    }
90923a0898aSmrg    pi = (fsPropInfo *) buf;
91023a0898aSmrg    buf += SIZEOF (fsPropInfo);
9119d21a897Sspz    bufleft -= SIZEOF(fsPropInfo);
91241c30155Smrg
9139d21a897Sspz    if ((bufleft / SIZEOF(fsPropOffset)) < pi->num_offsets)
9149d21a897Sspz    {
9157673729aSmrg	ret = -1;
9169d21a897Sspz#ifdef DEBUG
9177673729aSmrg	fprintf(stderr,
9187673729aSmrg		"fsQueryXInfo: bufleft (%ld) / SIZEOF(fsPropOffset) < %d\n",
9197673729aSmrg		bufleft, pi->num_offsets);
9209d21a897Sspz#endif
9217673729aSmrg	goto bail;
9229d21a897Sspz    }
92323a0898aSmrg    po = (fsPropOffset *) buf;
92423a0898aSmrg    buf += pi->num_offsets * SIZEOF(fsPropOffset);
9259d21a897Sspz    bufleft -= pi->num_offsets * SIZEOF(fsPropOffset);
92623a0898aSmrg
9279d21a897Sspz    if (bufleft < pi->data_len)
9289d21a897Sspz    {
9297673729aSmrg	ret = -1;
9309d21a897Sspz#ifdef DEBUG
9317673729aSmrg	fprintf(stderr,
9327673729aSmrg		"fsQueryXInfo: bufleft (%ld) < data_len (%d)\n",
9337673729aSmrg		bufleft, pi->data_len);
9349d21a897Sspz#endif
9357673729aSmrg	goto bail;
9369d21a897Sspz    }
93723a0898aSmrg    pd = (pointer) buf;
93823a0898aSmrg    buf += pi->data_len;
9399d21a897Sspz    bufleft -= pi->data_len;
94041c30155Smrg
94123a0898aSmrg    /* convert the properties and step over the reply */
94223a0898aSmrg    ret = _fs_convert_props(pi, po, pd, pInfo);
9439d21a897Sspz  bail:
94423a0898aSmrg    _fs_done_read (conn, rep->length << 2);
94541c30155Smrg
94623a0898aSmrg    if (ret == -1)
94723a0898aSmrg    {
94823a0898aSmrg	fs_cleanup_bfont (bfont);
94923a0898aSmrg	return AllocError;
95023a0898aSmrg    }
95123a0898aSmrg
95223a0898aSmrg    if (bfont->flags & FontReopen)
95323a0898aSmrg    {
95423a0898aSmrg	/* We're reopening a font that we lost because of a downed
95523a0898aSmrg	   connection.  In the interest of avoiding corruption from
95623a0898aSmrg	   opening a different font than the old one (we already have
95723a0898aSmrg	   its metrics, extents, and probably some of its glyphs),
95823a0898aSmrg	   verify that the metrics and properties all match.  */
95923a0898aSmrg
96023a0898aSmrg	if (fs_fonts_match (pInfo, &bfont->pfont->info))
96123a0898aSmrg	{
96223a0898aSmrg	    err = Successful;
96323a0898aSmrg	    bfont->state = FS_DONE_REPLY;
96423a0898aSmrg	}
96523a0898aSmrg	else
96623a0898aSmrg	{
96723a0898aSmrg	    fs_cleanup_bfont (bfont);
96823a0898aSmrg	    err = BadFontName;
96923a0898aSmrg	}
97023a0898aSmrg	_fs_free_props (pInfo);
97141c30155Smrg
97223a0898aSmrg	return err;
97323a0898aSmrg    }
97423a0898aSmrg
97523a0898aSmrg    /*
97623a0898aSmrg     * Ask for terminal format fonts if possible
97723a0898aSmrg     */
97823a0898aSmrg    if (bfont->pfont->info.terminalFont)
97923a0898aSmrg	bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
98023a0898aSmrg			 BitmapFormatImageRectMax);
98123a0898aSmrg
98223a0898aSmrg    /*
98323a0898aSmrg     * Figure out if the whole font should get loaded right now.
98423a0898aSmrg     */
98523a0898aSmrg    if (glyphCachingMode == CACHING_OFF ||
98641c30155Smrg	(glyphCachingMode == CACHE_16_BIT_GLYPHS
98723a0898aSmrg	 && !bfont->pfont->info.lastRow))
98823a0898aSmrg    {
98923a0898aSmrg	bfont->flags |= FontLoadAll;
99023a0898aSmrg    }
99141c30155Smrg
99223a0898aSmrg    /*
99341c30155Smrg     * Ready to send the query bitmaps; the terminal font bit has
99423a0898aSmrg     * been computed and glyphCaching has been considered
99523a0898aSmrg     */
99623a0898aSmrg    if (bfont->flags & FontLoadBitmaps)
99723a0898aSmrg    {
99823a0898aSmrg	fs_send_query_bitmaps (fpe, blockrec);
99923a0898aSmrg	_fs_flush (conn);
100023a0898aSmrg    }
100123a0898aSmrg
100223a0898aSmrg    bfont->state = FS_EXTENT_REPLY;
100323a0898aSmrg
100423a0898aSmrg    /*
100523a0898aSmrg     * Reset the blockrec for the next reply
100623a0898aSmrg     */
100723a0898aSmrg    blockrec->sequenceNumber = bfont->queryExtentsSequence;
100823a0898aSmrg    conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
100941c30155Smrg
101023a0898aSmrg    return StillWorking;
101123a0898aSmrg}
101223a0898aSmrg
101323a0898aSmrgstatic int
101423a0898aSmrgfs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
101523a0898aSmrg{
101623a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
101723a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
101823a0898aSmrg    FSFontDataPtr	    fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
101923a0898aSmrg    FSFontPtr		    fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
102023a0898aSmrg    fsQueryXExtents16Reply  *rep;
102123a0898aSmrg    char		    *buf;
102223a0898aSmrg    int			    i;
102323a0898aSmrg    int			    numExtents;
102423a0898aSmrg    int			    numInfos;
102523a0898aSmrg    int			    ret;
102623a0898aSmrg    Bool		    haveInk = FALSE; /* need separate ink metrics? */
102723a0898aSmrg    CharInfoPtr		    ci, pCI;
102823a0898aSmrg    char		    *fsci;
102923a0898aSmrg    fsXCharInfo		    fscilocal;
103023a0898aSmrg    FontInfoRec		    *fi = &bfont->pfont->info;
103123a0898aSmrg
103223a0898aSmrg    rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
10339d21a897Sspz    if (!rep || rep->type == FS_Error ||
10347673729aSmrg	(rep->length < LENGTHOF(fsQueryXExtents16Reply)))
103523a0898aSmrg    {
103623a0898aSmrg	if (ret == FSIO_BLOCK)
103723a0898aSmrg	    return StillWorking;
103823a0898aSmrg	if (rep)
103923a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
104023a0898aSmrg	fs_cleanup_bfont (bfont);
10417673729aSmrg	_fs_reply_failed (rep, fsQueryXExtents16Reply, "<");
104223a0898aSmrg	return BadFontName;
104323a0898aSmrg    }
104441c30155Smrg
104523a0898aSmrg    /* move the data over */
104623a0898aSmrg    /* need separate inkMetrics for fixed font server protocol version */
104723a0898aSmrg    numExtents = rep->num_extents;
104823a0898aSmrg    numInfos = numExtents;
104923a0898aSmrg    if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
105023a0898aSmrg    {
105123a0898aSmrg	numInfos *= 2;
105223a0898aSmrg	haveInk = TRUE;
105323a0898aSmrg    }
10549d21a897Sspz    if (numInfos >= (INT_MAX / sizeof(CharInfoRec))) {
10559d21a897Sspz#ifdef DEBUG
10567673729aSmrg	fprintf(stderr,
10577673729aSmrg		"fsQueryXExtents16: numInfos (%d) >= %ld\n",
10587673729aSmrg		numInfos, (INT_MAX / sizeof(CharInfoRec)));
10599d21a897Sspz#endif
10607673729aSmrg	pCI = NULL;
10619d21a897Sspz    }
10629d21a897Sspz    else if (numExtents > ((rep->length - LENGTHOF(fsQueryXExtents16Reply))
10637673729aSmrg			    / LENGTHOF(fsXCharInfo))) {
10649d21a897Sspz#ifdef DEBUG
10657673729aSmrg	fprintf(stderr,
10667673729aSmrg		"fsQueryXExtents16: numExtents (%d) > (%d - %d) / %d\n",
10677673729aSmrg		numExtents, rep->length,
10687673729aSmrg		LENGTHOF(fsQueryXExtents16Reply), LENGTHOF(fsXCharInfo));
10699d21a897Sspz#endif
10707673729aSmrg	pCI = NULL;
10719d21a897Sspz    }
10729d21a897Sspz    else
10737673729aSmrg	pCI = malloc(sizeof(CharInfoRec) * numInfos);
107423a0898aSmrg
107541c30155Smrg    if (!pCI)
107623a0898aSmrg    {
107723a0898aSmrg	_fs_done_read (conn, rep->length << 2);
107823a0898aSmrg	fs_cleanup_bfont(bfont);
107923a0898aSmrg	return AllocError;
108023a0898aSmrg    }
108123a0898aSmrg    fsfont->encoding = pCI;
108223a0898aSmrg    if (haveInk)
108323a0898aSmrg	fsfont->inkMetrics = pCI + numExtents;
108423a0898aSmrg    else
108523a0898aSmrg        fsfont->inkMetrics = pCI;
108623a0898aSmrg
108723a0898aSmrg    buf = (char *) rep;
108823a0898aSmrg    buf += SIZEOF (fsQueryXExtents16Reply);
108923a0898aSmrg    fsci = buf;
109041c30155Smrg
109123a0898aSmrg    fsd->glyphs_to_get = 0;
109223a0898aSmrg    ci = fsfont->inkMetrics;
109341c30155Smrg    for (i = 0; i < numExtents; i++)
109423a0898aSmrg    {
109523a0898aSmrg	memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
109623a0898aSmrg	_fs_convert_char_info(&fscilocal, &ci->metrics);
109723a0898aSmrg	/* Bounds check. */
109823a0898aSmrg	if (ci->metrics.ascent > fi->maxbounds.ascent)
109923a0898aSmrg	{
110023a0898aSmrg	    ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
110123a0898aSmrg		   fpe->name, fsd->name,
110223a0898aSmrg		   ci->metrics.ascent, fi->maxbounds.ascent);
110323a0898aSmrg	    ci->metrics.ascent = fi->maxbounds.ascent;
110423a0898aSmrg	}
110523a0898aSmrg	if (ci->metrics.descent > fi->maxbounds.descent)
110623a0898aSmrg	{
110723a0898aSmrg	    ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
110823a0898aSmrg		   fpe->name, fsd->name,
110923a0898aSmrg		   ci->metrics.descent, fi->maxbounds.descent);
111023a0898aSmrg	    ci->metrics.descent = fi->maxbounds.descent;
111123a0898aSmrg	}
111223a0898aSmrg	fsci = fsci + SIZEOF(fsXCharInfo);
111323a0898aSmrg	/* Initialize the bits field for later glyph-caching use */
111423a0898aSmrg	if (NONZEROMETRICS(&ci->metrics))
111523a0898aSmrg	{
111623a0898aSmrg	    if (!haveInk &&
111723a0898aSmrg		(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
111823a0898aSmrg		 ci->metrics.ascent == -ci->metrics.descent))
111923a0898aSmrg		pCI[i].bits = &_fs_glyph_zero_length;
112023a0898aSmrg	    else
112123a0898aSmrg	    {
112223a0898aSmrg		pCI[i].bits = &_fs_glyph_undefined;
112323a0898aSmrg		fsd->glyphs_to_get++;
112423a0898aSmrg	    }
112523a0898aSmrg	}
112623a0898aSmrg	else
112723a0898aSmrg	    pCI[i].bits = (char *)0;
112823a0898aSmrg	ci++;
112923a0898aSmrg    }
113023a0898aSmrg
113123a0898aSmrg    /* Done with reply */
113223a0898aSmrg    _fs_done_read (conn, rep->length << 2);
113341c30155Smrg
113423a0898aSmrg    /* build bitmap metrics, ImageRectMax style */
113523a0898aSmrg    if (haveInk)
113623a0898aSmrg    {
113723a0898aSmrg	CharInfoPtr ii;
113823a0898aSmrg
113923a0898aSmrg	ci = fsfont->encoding;
114023a0898aSmrg	ii = fsfont->inkMetrics;
114123a0898aSmrg	for (i = 0; i < numExtents; i++, ci++, ii++)
114223a0898aSmrg	{
114323a0898aSmrg	    if (NONZEROMETRICS(&ii->metrics))
114423a0898aSmrg	    {
114523a0898aSmrg		ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
114623a0898aSmrg		ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
114723a0898aSmrg		ci->metrics.ascent = FONT_MAX_ASCENT(fi);
114823a0898aSmrg		ci->metrics.descent = FONT_MAX_DESCENT(fi);
114923a0898aSmrg		ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
115023a0898aSmrg		ci->metrics.attributes = ii->metrics.attributes;
115123a0898aSmrg	    }
115223a0898aSmrg	    else
115323a0898aSmrg	    {
115423a0898aSmrg		ci->metrics = ii->metrics;
115523a0898aSmrg	    }
115623a0898aSmrg	    /* Bounds check. */
115723a0898aSmrg	    if (ci->metrics.ascent > fi->maxbounds.ascent)
115823a0898aSmrg	    {
115923a0898aSmrg		ErrorF("fserve: warning: %s %s ascent (%d) "
116023a0898aSmrg		       "> maxascent (%d)\n",
116123a0898aSmrg		       fpe->name, fsd->name,
116223a0898aSmrg		       ci->metrics.ascent, fi->maxbounds.ascent);
116323a0898aSmrg		ci->metrics.ascent = fi->maxbounds.ascent;
116423a0898aSmrg	    }
116523a0898aSmrg	    if (ci->metrics.descent > fi->maxbounds.descent)
116623a0898aSmrg	    {
116723a0898aSmrg		ErrorF("fserve: warning: %s %s descent (%d) "
116823a0898aSmrg		       "> maxdescent (%d)\n",
116923a0898aSmrg		       fpe->name, fsd->name,
117023a0898aSmrg		       ci->metrics.descent, fi->maxbounds.descent);
117123a0898aSmrg		ci->metrics.descent = fi->maxbounds.descent;
117223a0898aSmrg	    }
117323a0898aSmrg	}
117423a0898aSmrg    }
117523a0898aSmrg    {
117623a0898aSmrg	unsigned int r, c, numCols, firstCol;
117723a0898aSmrg
117823a0898aSmrg	firstCol = bfont->pfont->info.firstCol;
117923a0898aSmrg	numCols = bfont->pfont->info.lastCol - firstCol + 1;
118023a0898aSmrg	c = bfont->pfont->info.defaultCh;
118123a0898aSmrg	fsfont->pDefault = 0;
118223a0898aSmrg	if (bfont->pfont->info.lastRow)
118323a0898aSmrg	{
118423a0898aSmrg	    r = c >> 8;
118523a0898aSmrg	    r -= bfont->pfont->info.firstRow;
118623a0898aSmrg	    c &= 0xff;
118723a0898aSmrg	    c -= firstCol;
118823a0898aSmrg	    if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
118923a0898aSmrg		c < numCols)
119023a0898aSmrg		fsfont->pDefault = &pCI[r * numCols + c];
119123a0898aSmrg	}
119223a0898aSmrg	else
119323a0898aSmrg	{
119423a0898aSmrg	    c -= firstCol;
119523a0898aSmrg	    if (c < numCols)
119623a0898aSmrg		fsfont->pDefault = &pCI[c];
119723a0898aSmrg	}
119823a0898aSmrg    }
119923a0898aSmrg    bfont->state = FS_GLYPHS_REPLY;
120023a0898aSmrg
120141c30155Smrg    if (bfont->flags & FontLoadBitmaps)
120223a0898aSmrg    {
120323a0898aSmrg	/*
120423a0898aSmrg	 * Reset the blockrec for the next reply
120523a0898aSmrg	 */
120623a0898aSmrg	blockrec->sequenceNumber = bfont->queryBitmapsSequence;
120723a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
120823a0898aSmrg	return StillWorking;
120923a0898aSmrg    }
121023a0898aSmrg    return Successful;
121123a0898aSmrg}
121223a0898aSmrg
121323a0898aSmrg#ifdef DEBUG
12147673729aSmrgstatic const char *fs_open_states[] = {
121523a0898aSmrg    "OPEN_REPLY  ",
121623a0898aSmrg    "INFO_REPLY  ",
121723a0898aSmrg    "EXTENT_REPLY",
121823a0898aSmrg    "GLYPHS_REPLY",
121923a0898aSmrg    "DONE_REPLY  ",
122023a0898aSmrg    "DEPENDING   ",
122123a0898aSmrg};
122223a0898aSmrg#endif
122323a0898aSmrg
122423a0898aSmrgstatic int
122523a0898aSmrgfs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
122623a0898aSmrg{
122723a0898aSmrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
122823a0898aSmrg    int			err;
122923a0898aSmrg
123023a0898aSmrg#ifdef DEBUG
123123a0898aSmrg    fprintf (stderr, "fs_do_open_font state %s %s\n",
123241c30155Smrg	     fs_open_states[bfont->state],
123323a0898aSmrg	     ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
123423a0898aSmrg#endif
123523a0898aSmrg    err = BadFontName;
123623a0898aSmrg    switch (bfont->state) {
123723a0898aSmrg    case FS_OPEN_REPLY:
123823a0898aSmrg	err = fs_read_open_font(fpe, blockrec);
123923a0898aSmrg	if (err != StillWorking) {	/* already loaded, or error */
124023a0898aSmrg	    /* if font's already loaded, massage error code */
124123a0898aSmrg	    switch (bfont->state) {
124223a0898aSmrg	    case FS_DONE_REPLY:
124323a0898aSmrg		err = Successful;
124423a0898aSmrg		break;
124523a0898aSmrg	    case FS_DEPENDING:
124623a0898aSmrg		err = StillWorking;
124723a0898aSmrg		break;
124823a0898aSmrg	    }
124923a0898aSmrg	}
125023a0898aSmrg	break;
125123a0898aSmrg    case FS_INFO_REPLY:
125223a0898aSmrg	err = fs_read_query_info(fpe, blockrec);
125323a0898aSmrg	break;
125423a0898aSmrg    case FS_EXTENT_REPLY:
125523a0898aSmrg	err = fs_read_extent_info(fpe, blockrec);
125623a0898aSmrg	break;
125723a0898aSmrg    case FS_GLYPHS_REPLY:
125823a0898aSmrg	if (bfont->flags & FontLoadBitmaps)
125923a0898aSmrg	    err = fs_read_glyphs(fpe, blockrec);
126023a0898aSmrg	break;
126123a0898aSmrg    case FS_DEPENDING:		/* can't happen */
126223a0898aSmrg    default:
126323a0898aSmrg	break;
126423a0898aSmrg    }
126523a0898aSmrg#ifdef DEBUG
126623a0898aSmrg    fprintf (stderr, "fs_do_open_font err %d\n", err);
126723a0898aSmrg#endif
126841c30155Smrg    if (err != StillWorking)
126923a0898aSmrg    {
127023a0898aSmrg	bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
127141c30155Smrg	while ((blockrec = blockrec->depending))
127223a0898aSmrg	{
127323a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
127423a0898aSmrg	    bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
127523a0898aSmrg	}
127623a0898aSmrg    }
127723a0898aSmrg    return err;
127823a0898aSmrg}
127923a0898aSmrg
128023a0898aSmrgvoid
128123a0898aSmrg_fs_mark_block (FSFpePtr conn, CARD32 mask)
128223a0898aSmrg{
128323a0898aSmrg    conn->blockState |= mask;
128423a0898aSmrg    fs_blockState |= mask;
128523a0898aSmrg}
128623a0898aSmrg
128723a0898aSmrgvoid
128823a0898aSmrg_fs_unmark_block (FSFpePtr conn, CARD32 mask)
128923a0898aSmrg{
129023a0898aSmrg    FSFpePtr	c;
129141c30155Smrg
129223a0898aSmrg    if (conn->blockState & mask)
129323a0898aSmrg    {
129423a0898aSmrg	conn->blockState &= ~mask;
129523a0898aSmrg	fs_blockState = 0;
129623a0898aSmrg	for (c = fs_fpes; c; c = c->next)
129723a0898aSmrg	    fs_blockState |= c->blockState;
129823a0898aSmrg    }
129923a0898aSmrg}
130023a0898aSmrg
130123a0898aSmrg/* ARGSUSED */
130223a0898aSmrgstatic void
130323a0898aSmrgfs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
130423a0898aSmrg{
130523a0898aSmrg    static struct timeval block_timeout;
130623a0898aSmrg    CARD32	now, earliest, wakeup;
130723a0898aSmrg    int		soonest;
130823a0898aSmrg    FSFpePtr    conn;
130923a0898aSmrg
131041c30155Smrg    XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
131123a0898aSmrg	      &_fs_fd_mask);
131223a0898aSmrg    /*
131323a0898aSmrg     * Flush all pending output
131423a0898aSmrg     */
131523a0898aSmrg    if (fs_blockState & FS_PENDING_WRITE)
131623a0898aSmrg	for (conn = fs_fpes; conn; conn = conn->next)
131723a0898aSmrg	    if (conn->blockState & FS_PENDING_WRITE)
131823a0898aSmrg		_fs_flush (conn);
131923a0898aSmrg    /*
132023a0898aSmrg     * Check for any fpe with a complete reply, set sleep time to zero
132123a0898aSmrg     */
132223a0898aSmrg    if (fs_blockState & FS_COMPLETE_REPLY)
132323a0898aSmrg    {
132423a0898aSmrg	block_timeout.tv_sec = 0;
132523a0898aSmrg	block_timeout.tv_usec = 0;
132623a0898aSmrg	if (*wt == NULL)
132723a0898aSmrg	    *wt = &block_timeout;
132823a0898aSmrg	else
132923a0898aSmrg	    **wt = block_timeout;
133023a0898aSmrg    }
133123a0898aSmrg    /*
133223a0898aSmrg     * Walk through fpe list computing sleep time
133323a0898aSmrg     */
133423a0898aSmrg    else if (fs_blockState & (FS_BROKEN_WRITE|
133523a0898aSmrg			      FS_BROKEN_CONNECTION|
133623a0898aSmrg			      FS_PENDING_REPLY|
133723a0898aSmrg			      FS_RECONNECTING))
133823a0898aSmrg    {
133923a0898aSmrg	now = GetTimeInMillis ();
134023a0898aSmrg	earliest = now + 10000000;
134123a0898aSmrg	for (conn = fs_fpes; conn; conn = conn->next)
134223a0898aSmrg	{
134323a0898aSmrg	    if (conn->blockState & FS_RECONNECTING)
134423a0898aSmrg	    {
134523a0898aSmrg		wakeup = conn->blockedConnectTime;
134623a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
134723a0898aSmrg		    earliest = wakeup;
134823a0898aSmrg	    }
134923a0898aSmrg	    if (conn->blockState & FS_BROKEN_CONNECTION)
135023a0898aSmrg	    {
135123a0898aSmrg		wakeup = conn->brokenConnectionTime;
135223a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
135323a0898aSmrg		    earliest = wakeup;
135423a0898aSmrg	    }
135523a0898aSmrg	    if (conn->blockState & FS_BROKEN_WRITE)
135623a0898aSmrg	    {
135723a0898aSmrg		wakeup = conn->brokenWriteTime;
135823a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
135923a0898aSmrg		    earliest = wakeup;
136023a0898aSmrg	    }
136123a0898aSmrg	    if (conn->blockState & FS_PENDING_REPLY)
136223a0898aSmrg	    {
136323a0898aSmrg		wakeup = conn->blockedReplyTime;
136423a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
136523a0898aSmrg		    earliest = wakeup;
136623a0898aSmrg	    }
136723a0898aSmrg	}
136823a0898aSmrg	soonest = earliest - now;
136923a0898aSmrg	if (soonest < 0)
137023a0898aSmrg	    soonest = 0;
137123a0898aSmrg	block_timeout.tv_sec = soonest / 1000;
137223a0898aSmrg	block_timeout.tv_usec = (soonest % 1000) * 1000;
137323a0898aSmrg	if (*wt == NULL)
137423a0898aSmrg	    *wt = &block_timeout;
137523a0898aSmrg	else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
137623a0898aSmrg	    **wt = block_timeout;
137723a0898aSmrg    }
137823a0898aSmrg}
137923a0898aSmrg
138023a0898aSmrgstatic void
138123a0898aSmrgfs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
138223a0898aSmrg{
138341c30155Smrg    if (rep->type == FS_Event && rep->data1 == KeepAlive)
138423a0898aSmrg    {
138523a0898aSmrg	fsNoopReq   req;
138623a0898aSmrg
138723a0898aSmrg	/* ping it back */
138823a0898aSmrg	req.reqType = FS_Noop;
138923a0898aSmrg	req.length = SIZEOF(fsNoopReq) >> 2;
139023a0898aSmrg	_fs_add_req_log(conn, FS_Noop);
139123a0898aSmrg	_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
139223a0898aSmrg    }
139323a0898aSmrg    /* this should suck up unexpected replies and events */
139423a0898aSmrg    _fs_done_read (conn, rep->length << 2);
139523a0898aSmrg}
139623a0898aSmrg
139723a0898aSmrgstatic void
139823a0898aSmrgfs_read_reply (FontPathElementPtr fpe, pointer client)
139923a0898aSmrg{
140023a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
140123a0898aSmrg    FSBlockDataPtr  blockrec;
140223a0898aSmrg    int		    ret;
140323a0898aSmrg    int		    err;
140423a0898aSmrg    fsGenericReply  *rep;
140541c30155Smrg
140623a0898aSmrg    if ((rep = fs_get_reply (conn, &ret)))
140723a0898aSmrg    {
140823a0898aSmrg	_fs_add_rep_log (conn, rep);
140941c30155Smrg	for (blockrec = conn->blockedRequests;
141041c30155Smrg	     blockrec;
141141c30155Smrg	     blockrec = blockrec->next)
141223a0898aSmrg	{
141323a0898aSmrg	    if (blockrec->sequenceNumber == rep->sequenceNumber)
141423a0898aSmrg		break;
141523a0898aSmrg	}
141623a0898aSmrg	err = Successful;
141741c30155Smrg	if (!blockrec)
141823a0898aSmrg	{
141923a0898aSmrg	    fs_handle_unexpected(conn, rep);
142023a0898aSmrg	}
142123a0898aSmrg	else
142223a0898aSmrg	{
142341c30155Smrg	    /*
142441c30155Smrg	     * go read it, and if we're done,
142541c30155Smrg	     * wake up the appropriate client
142623a0898aSmrg	     */
142723a0898aSmrg	    switch (blockrec->type) {
142823a0898aSmrg	    case FS_OPEN_FONT:
142923a0898aSmrg		blockrec->errcode = fs_do_open_font(fpe, blockrec);
143023a0898aSmrg		break;
143123a0898aSmrg	    case FS_LOAD_GLYPHS:
143223a0898aSmrg		blockrec->errcode = fs_read_glyphs(fpe, blockrec);
143323a0898aSmrg		break;
143423a0898aSmrg	    case FS_LIST_FONTS:
143523a0898aSmrg		blockrec->errcode = fs_read_list(fpe, blockrec);
143623a0898aSmrg		break;
143723a0898aSmrg	    case FS_LIST_WITH_INFO:
143823a0898aSmrg		blockrec->errcode = fs_read_list_info(fpe, blockrec);
143923a0898aSmrg		break;
144023a0898aSmrg	    default:
144123a0898aSmrg		break;
144223a0898aSmrg	    }
144323a0898aSmrg	    err = blockrec->errcode;
144423a0898aSmrg	    if (err != StillWorking)
144523a0898aSmrg	    {
144641c30155Smrg		while (blockrec)
144723a0898aSmrg		{
144823a0898aSmrg		    blockrec->errcode = err;
144923a0898aSmrg		    if (client != blockrec->client)
145023a0898aSmrg			ClientSignal(blockrec->client);
145123a0898aSmrg		    blockrec = blockrec->depending;
145223a0898aSmrg		}
145323a0898aSmrg		_fs_unmark_block (conn, FS_PENDING_REPLY);
145423a0898aSmrg	    }
145523a0898aSmrg	}
145623a0898aSmrg	if (fs_reply_ready (conn))
145723a0898aSmrg	    _fs_mark_block (conn, FS_COMPLETE_REPLY);
145823a0898aSmrg	else
145923a0898aSmrg	    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
146023a0898aSmrg    }
146123a0898aSmrg}
146223a0898aSmrg
146323a0898aSmrgstatic int
146423a0898aSmrgfs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
146523a0898aSmrg{
146623a0898aSmrg    fd_set	    *LastSelectMask = (fd_set *) mask;
146723a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
146823a0898aSmrg
146941c30155Smrg    /*
147023a0898aSmrg     * Don't continue if the fd is -1 (which will be true when the
147123a0898aSmrg     * font server terminates
147223a0898aSmrg     */
147323a0898aSmrg    if ((conn->blockState & FS_RECONNECTING))
147423a0898aSmrg	_fs_check_reconnect (conn);
147523a0898aSmrg    else if ((conn->blockState & FS_COMPLETE_REPLY) ||
147623a0898aSmrg	     (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
147723a0898aSmrg	fs_read_reply (fpe, 0);
147823a0898aSmrg    if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
147923a0898aSmrg	_fs_do_blocked (conn);
148023a0898aSmrg#ifdef DEBUG
148123a0898aSmrg    {
148223a0898aSmrg	FSBlockDataPtr	    blockrec;
148323a0898aSmrg	FSBlockedFontPtr    bfont;
148423a0898aSmrg	static CARD32	    lastState;
148523a0898aSmrg	static FSBlockDataPtr	lastBlock;
148623a0898aSmrg
148723a0898aSmrg	if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
148823a0898aSmrg	{
148923a0898aSmrg	    fprintf (stderr, "  Block State 0x%x\n", (int) conn->blockState);
149023a0898aSmrg	    lastState = conn->blockState;
149123a0898aSmrg	    lastBlock = conn->blockedRequests;
149223a0898aSmrg	}
149323a0898aSmrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
149423a0898aSmrg	{
149523a0898aSmrg	    switch (blockrec->type) {
149623a0898aSmrg	    case FS_OPEN_FONT:
149723a0898aSmrg		bfont = (FSBlockedFontPtr) blockrec->data;
149823a0898aSmrg		fprintf (stderr, "  Blocked font errcode %d sequence %d state %s %s\n",
149923a0898aSmrg			 blockrec->errcode,
150023a0898aSmrg			 blockrec->sequenceNumber,
150123a0898aSmrg			 fs_open_states[bfont->state],
150241c30155Smrg			 bfont->pfont ?
150323a0898aSmrg			 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
150423a0898aSmrg			 "<freed>");
150523a0898aSmrg		break;
150623a0898aSmrg	    case FS_LIST_FONTS:
150723a0898aSmrg		fprintf (stderr, "  Blocked list errcode %d sequence %d\n",
150823a0898aSmrg			 blockrec->errcode, blockrec->sequenceNumber);
150923a0898aSmrg		break;
151023a0898aSmrg	    default:
151123a0898aSmrg		fprintf (stderr, "  Blocked type %d errcode %d sequence %d\n",
151223a0898aSmrg			 blockrec->type,
151323a0898aSmrg			 blockrec->errcode,
151423a0898aSmrg			 blockrec->sequenceNumber);
151523a0898aSmrg		break;
151623a0898aSmrg	    }
151723a0898aSmrg	}
151823a0898aSmrg    }
151941c30155Smrg#endif
152023a0898aSmrg    return FALSE;
152123a0898aSmrg}
152223a0898aSmrg
152323a0898aSmrg/*
152423a0898aSmrg * Notice a dead connection and prepare for reconnect
152523a0898aSmrg */
152623a0898aSmrg
152723a0898aSmrgvoid
152823a0898aSmrg_fs_connection_died(FSFpePtr conn)
152923a0898aSmrg{
153023a0898aSmrg    if (conn->blockState & FS_BROKEN_CONNECTION)
153123a0898aSmrg	return;
153223a0898aSmrg    fs_close_conn(conn);
153323a0898aSmrg    conn->brokenConnectionTime = GetTimeInMillis ();
153423a0898aSmrg    _fs_mark_block (conn, FS_BROKEN_CONNECTION);
153523a0898aSmrg    _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
153623a0898aSmrg}
153723a0898aSmrg
153823a0898aSmrg/*
153923a0898aSmrg * Signal clients that the connection has come back up
154023a0898aSmrg */
154123a0898aSmrgstatic int
154223a0898aSmrg_fs_restart_connection(FSFpePtr conn)
154323a0898aSmrg{
154423a0898aSmrg    FSBlockDataPtr block;
154523a0898aSmrg
154623a0898aSmrg    _fs_unmark_block (conn, FS_GIVE_UP);
154741c30155Smrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
154823a0898aSmrg    {
154923a0898aSmrg	if (block->errcode == StillWorking)
155023a0898aSmrg	{
155123a0898aSmrg	    ClientSignal(block->client);
155223a0898aSmrg	    fs_abort_blockrec(conn, block);
155323a0898aSmrg	}
155423a0898aSmrg    }
155523a0898aSmrg    return TRUE;
155623a0898aSmrg}
155723a0898aSmrg
155823a0898aSmrg/*
155923a0898aSmrg * Declare this font server connection useless
156023a0898aSmrg */
156123a0898aSmrgstatic void
156223a0898aSmrg_fs_giveup (FSFpePtr conn)
156323a0898aSmrg{
156423a0898aSmrg    FSBlockDataPtr  block;
156523a0898aSmrg
156623a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
156723a0898aSmrg	return;
156823a0898aSmrg#ifdef DEBUG
156923a0898aSmrg    fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
157023a0898aSmrg#endif
157123a0898aSmrg    _fs_mark_block (conn, FS_GIVE_UP);
157241c30155Smrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
157323a0898aSmrg    {
157423a0898aSmrg	if (block->errcode == StillWorking)
157523a0898aSmrg	{
157623a0898aSmrg	    ClientSignal (block->client);
157723a0898aSmrg	    fs_abort_blockrec (conn, block);
157823a0898aSmrg	}
157923a0898aSmrg    }
158023a0898aSmrg    if (conn->fs_fd >= 0)
158123a0898aSmrg	_fs_connection_died (conn);
158223a0898aSmrg}
158323a0898aSmrg
158423a0898aSmrgstatic void
158523a0898aSmrg_fs_do_blocked (FSFpePtr conn)
158623a0898aSmrg{
158723a0898aSmrg    CARD32      now;
158823a0898aSmrg
158923a0898aSmrg    now = GetTimeInMillis ();
159023a0898aSmrg    if ((conn->blockState & FS_PENDING_REPLY) &&
159123a0898aSmrg	TimeCmp (conn->blockedReplyTime, <=, now))
159223a0898aSmrg    {
159323a0898aSmrg	_fs_giveup (conn);
159423a0898aSmrg    }
159541c30155Smrg    else
159623a0898aSmrg    {
159723a0898aSmrg	if (conn->blockState & FS_BROKEN_CONNECTION)
159823a0898aSmrg	{
159923a0898aSmrg	    /* Try to reconnect broken connections */
160023a0898aSmrg	    if (TimeCmp (conn->brokenConnectionTime, <=, now))
160123a0898aSmrg		_fs_start_reconnect (conn);
160223a0898aSmrg	}
160323a0898aSmrg	else if (conn->blockState & FS_BROKEN_WRITE)
160423a0898aSmrg	{
160523a0898aSmrg	    /* Try to flush blocked connections */
160623a0898aSmrg	    if (TimeCmp (conn->brokenWriteTime, <=, now))
160723a0898aSmrg		_fs_flush (conn);
160823a0898aSmrg	}
160923a0898aSmrg    }
161023a0898aSmrg}
161123a0898aSmrg
161223a0898aSmrg/*
161323a0898aSmrg * sends the actual request out
161423a0898aSmrg */
161523a0898aSmrg/* ARGSUSED */
161623a0898aSmrgstatic int
161741c30155Smrgfs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
161841c30155Smrg		  char *name, int namelen,
161941c30155Smrg		  fsBitmapFormat format, fsBitmapFormatMask fmask,
162023a0898aSmrg		  XID id, FontPtr *ppfont)
162123a0898aSmrg{
162223a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
162323a0898aSmrg    FontPtr		    font;
162423a0898aSmrg    FSBlockDataPtr	    blockrec = NULL;
162523a0898aSmrg    FSBlockedFontPtr	    bfont;
162623a0898aSmrg    FSFontDataPtr	    fsd;
162723a0898aSmrg    fsOpenBitmapFontReq	    openreq;
162823a0898aSmrg    fsQueryXInfoReq	    inforeq;
162923a0898aSmrg    fsQueryXExtents16Req    extreq;
163023a0898aSmrg    int			    err;
163123a0898aSmrg    unsigned char	    buf[1024];
163223a0898aSmrg
163323a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
163423a0898aSmrg	return BadFontName;
163541c30155Smrg
163623a0898aSmrg    if (namelen <= 0 || namelen > sizeof (buf) - 1)
163723a0898aSmrg	return BadFontName;
163841c30155Smrg
163923a0898aSmrg    /*
164023a0898aSmrg     * Get the font structure put together, either by reusing
164123a0898aSmrg     * the existing one or creating a new one
164223a0898aSmrg     */
164323a0898aSmrg    if (flags & FontReopen)
164423a0898aSmrg    {
164523a0898aSmrg	Atom	nameatom, fn = None;
164623a0898aSmrg	int	i;
164723a0898aSmrg
164823a0898aSmrg	font = *ppfont;
164923a0898aSmrg	fsd = (FSFontDataPtr)font->fpePrivate;
165023a0898aSmrg	/* This is an attempt to reopen a font.  Did the font have a
165123a0898aSmrg	   NAME property? */
165223a0898aSmrg	if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
165323a0898aSmrg	{
165423a0898aSmrg	    for (i = 0; i < font->info.nprops; i++)
165523a0898aSmrg		if (font->info.props[i].name == nameatom &&
165623a0898aSmrg		    font->info.isStringProp[i])
165723a0898aSmrg		{
165823a0898aSmrg		    fn = font->info.props[i].value;
165923a0898aSmrg		    break;
166023a0898aSmrg		}
166123a0898aSmrg	}
166223a0898aSmrg	if (fn == None || !(name = NameForAtom(fn)))
166323a0898aSmrg	{
166423a0898aSmrg	    name = fsd->name;
166523a0898aSmrg	    namelen = fsd->namelen;
166623a0898aSmrg	}
166723a0898aSmrg	else
166823a0898aSmrg	    namelen = strlen(name);
166923a0898aSmrg    }
167023a0898aSmrg    else
167123a0898aSmrg    {
167223a0898aSmrg	font = fs_create_font (fpe, name, namelen, format, fmask);
167323a0898aSmrg	if (!font)
167423a0898aSmrg	    return AllocError;
167541c30155Smrg
167623a0898aSmrg	fsd = (FSFontDataPtr)font->fpePrivate;
167723a0898aSmrg    }
167841c30155Smrg
167923a0898aSmrg    /* make a new block record, and add it to the end of the list */
168023a0898aSmrg    blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
168123a0898aSmrg    if (!blockrec)
168223a0898aSmrg    {
168323a0898aSmrg	if (!(flags & FontReopen))
168423a0898aSmrg	    (*font->unload_font) (font);
168523a0898aSmrg	return AllocError;
168623a0898aSmrg    }
168741c30155Smrg
168823a0898aSmrg    /*
168923a0898aSmrg     * Must check this before generating any protocol, otherwise we'll
169023a0898aSmrg     * mess up a reconnect in progress
169123a0898aSmrg     */
169223a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
169323a0898aSmrg    {
169423a0898aSmrg	_fs_pending_reply (conn);
169523a0898aSmrg	return Suspended;
169623a0898aSmrg    }
169741c30155Smrg
169823a0898aSmrg    fsd->generation = conn->generation;
169923a0898aSmrg
170023a0898aSmrg    bfont = (FSBlockedFontPtr) blockrec->data;
170123a0898aSmrg    bfont->fontid = fsd->fontid;
170223a0898aSmrg    bfont->pfont = font;
170323a0898aSmrg    bfont->state = FS_OPEN_REPLY;
170423a0898aSmrg    bfont->flags = flags;
170523a0898aSmrg    bfont->format = fsd->format;
170623a0898aSmrg    bfont->clients_depending = (FSClientsDependingPtr)0;
170723a0898aSmrg    bfont->freeFont = (flags & FontReopen) == 0;
170823a0898aSmrg
170923a0898aSmrg    _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
171023a0898aSmrg    _fs_client_resolution(conn);
171123a0898aSmrg
171223a0898aSmrg    /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
171323a0898aSmrg    buf[0] = (unsigned char) namelen;
171423a0898aSmrg    memcpy(&buf[1], name, namelen);
171523a0898aSmrg    openreq.reqType = FS_OpenBitmapFont;
17167f7f5e4eSmrg    openreq.pad = 0;
171723a0898aSmrg    openreq.fid = fsd->fontid;
171823a0898aSmrg    openreq.format_hint = fsd->format;
171923a0898aSmrg    openreq.format_mask = fsd->fmask;
172023a0898aSmrg    openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
172123a0898aSmrg
172223a0898aSmrg    _fs_add_req_log(conn, FS_OpenBitmapFont);
172323a0898aSmrg    _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
172423a0898aSmrg    _fs_write_pad(conn, (char *) buf, namelen + 1);
172523a0898aSmrg
172623a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
172741c30155Smrg
172823a0898aSmrg    inforeq.reqType = FS_QueryXInfo;
17297f7f5e4eSmrg    inforeq.pad = 0;
173023a0898aSmrg    inforeq.id = fsd->fontid;
173123a0898aSmrg    inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
173223a0898aSmrg
173323a0898aSmrg    bfont->queryInfoSequence = conn->current_seq + 1;
173441c30155Smrg
173523a0898aSmrg    _fs_add_req_log(conn, FS_QueryXInfo);
173623a0898aSmrg    _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
173741c30155Smrg
173823a0898aSmrg    if (!(bfont->flags & FontReopen))
173923a0898aSmrg    {
174023a0898aSmrg	extreq.reqType = FS_QueryXExtents16;
174123a0898aSmrg	extreq.range = fsTrue;
174223a0898aSmrg	extreq.fid = fsd->fontid;
174323a0898aSmrg	extreq.num_ranges = 0;
174423a0898aSmrg	extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
174541c30155Smrg
174623a0898aSmrg	bfont->queryExtentsSequence = conn->current_seq + 1;
174741c30155Smrg
174823a0898aSmrg	_fs_add_req_log(conn, FS_QueryXExtents16);
174923a0898aSmrg	_fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
175023a0898aSmrg    }
175141c30155Smrg
175223a0898aSmrg#ifdef NCD
175341c30155Smrg    if (configData.ExtendedFontDiags)
175423a0898aSmrg    {
175523a0898aSmrg	memcpy(buf, name, MIN(256, namelen));
175623a0898aSmrg	buf[MIN(256, namelen)] = '\0';
175723a0898aSmrg	printf("Requesting font \"%s\" from font server \"%s\"\n",
175823a0898aSmrg	       buf, font->fpe->name);
175923a0898aSmrg    }
176023a0898aSmrg#endif
176123a0898aSmrg    _fs_prepare_for_reply (conn);
176241c30155Smrg
176323a0898aSmrg    err = blockrec->errcode;
176423a0898aSmrg    if (bfont->flags & FontOpenSync)
176523a0898aSmrg    {
176623a0898aSmrg	while (blockrec->errcode == StillWorking)
176723a0898aSmrg	{
176823a0898aSmrg	    if (fs_await_reply (conn) != FSIO_READY)
176923a0898aSmrg	    {
177023a0898aSmrg		blockrec->errcode = BadFontName;
177123a0898aSmrg		break;
177223a0898aSmrg	    }
177323a0898aSmrg	    fs_read_reply (font->fpe, client);
177423a0898aSmrg	}
177523a0898aSmrg	err = blockrec->errcode;
177623a0898aSmrg	if (err == Successful)
177723a0898aSmrg	    *ppfont = bfont->pfont;
177823a0898aSmrg	else
177923a0898aSmrg	    fs_cleanup_bfont (bfont);
178023a0898aSmrg	bfont->freeFont = FALSE;
178123a0898aSmrg	_fs_remove_block_rec (conn, blockrec);
178223a0898aSmrg    }
178323a0898aSmrg    return err == StillWorking ? Suspended : err;
178423a0898aSmrg}
178523a0898aSmrg
178623a0898aSmrgstatic void
178723a0898aSmrgfs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
178823a0898aSmrg{
178923a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
179023a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
179123a0898aSmrg    fsQueryXBitmaps16Req    bitreq;
179223a0898aSmrg
179323a0898aSmrg    /* send the request */
179423a0898aSmrg    bitreq.reqType = FS_QueryXBitmaps16;
179523a0898aSmrg    bitreq.fid = bfont->fontid;
179623a0898aSmrg    bitreq.format = bfont->format;
179723a0898aSmrg    bitreq.range = TRUE;
179823a0898aSmrg    bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
179923a0898aSmrg    bitreq.num_ranges = 0;
180023a0898aSmrg
180123a0898aSmrg    bfont->queryBitmapsSequence = conn->current_seq + 1;
180241c30155Smrg
180323a0898aSmrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
180423a0898aSmrg    _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
180523a0898aSmrg}
180623a0898aSmrg
180723a0898aSmrg/* ARGSUSED */
180823a0898aSmrgstatic int
180941c30155Smrgfs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
181041c30155Smrg	     char *name, int namelen,
181141c30155Smrg	     fsBitmapFormat format, fsBitmapFormatMask fmask,
181223a0898aSmrg	     XID id, FontPtr *ppfont,
181323a0898aSmrg	     char **alias, FontPtr non_cachable_font)
181423a0898aSmrg{
181523a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
181623a0898aSmrg    FSBlockDataPtr	blockrec;
181723a0898aSmrg    FSBlockedFontPtr	bfont;
181823a0898aSmrg    int			err;
181923a0898aSmrg
182023a0898aSmrg    /* libfont interface expects ImageRectMin glyphs */
182123a0898aSmrg    format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
182223a0898aSmrg
182323a0898aSmrg    *alias = (char *) 0;
182423a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
182523a0898aSmrg    {
182641c30155Smrg	if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
182723a0898aSmrg	{
182823a0898aSmrg	    err = blockrec->errcode;
182923a0898aSmrg	    if (err == StillWorking)
183023a0898aSmrg		return Suspended;
183141c30155Smrg
183223a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
183323a0898aSmrg	    if (err == Successful)
183423a0898aSmrg		*ppfont = bfont->pfont;
183523a0898aSmrg	    else
183623a0898aSmrg		fs_cleanup_bfont (bfont);
183723a0898aSmrg	    _fs_remove_block_rec (conn, blockrec);
183823a0898aSmrg	    return err;
183923a0898aSmrg	}
184023a0898aSmrg    }
184123a0898aSmrg    return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
184223a0898aSmrg			     id, ppfont);
184323a0898aSmrg}
184423a0898aSmrg
184523a0898aSmrg/* ARGSUSED */
184623a0898aSmrgstatic int
184723a0898aSmrgfs_send_close_font(FontPathElementPtr fpe, Font id)
184823a0898aSmrg{
184923a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
185023a0898aSmrg    fsCloseReq  req;
185123a0898aSmrg
185223a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
185323a0898aSmrg	return Successful;
185423a0898aSmrg    /* tell the font server to close the font */
185523a0898aSmrg    req.reqType = FS_CloseFont;
18567f7f5e4eSmrg    req.pad = 0;
185723a0898aSmrg    req.length = SIZEOF(fsCloseReq) >> 2;
185823a0898aSmrg    req.id = id;
185923a0898aSmrg    _fs_add_req_log(conn, FS_CloseFont);
186023a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
186123a0898aSmrg
186223a0898aSmrg    return Successful;
186323a0898aSmrg}
186423a0898aSmrg
186523a0898aSmrg/* ARGSUSED */
186623a0898aSmrgstatic void
186723a0898aSmrgfs_close_font(FontPathElementPtr fpe, FontPtr pfont)
186823a0898aSmrg{
186923a0898aSmrg    FSFontDataPtr   fsd = (FSFontDataPtr) pfont->fpePrivate;
187023a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
187123a0898aSmrg
187223a0898aSmrg    if (conn->generation == fsd->generation)
187323a0898aSmrg	fs_send_close_font(fpe, fsd->fontid);
187423a0898aSmrg
187523a0898aSmrg#ifdef DEBUG
187623a0898aSmrg    {
187723a0898aSmrg	FSBlockDataPtr	    blockrec;
187823a0898aSmrg	FSBlockedFontPtr    bfont;
187923a0898aSmrg
188023a0898aSmrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
188123a0898aSmrg	{
188223a0898aSmrg	    if (blockrec->type == FS_OPEN_FONT)
188323a0898aSmrg	    {
188423a0898aSmrg		bfont = (FSBlockedFontPtr) blockrec->data;
188523a0898aSmrg		if (bfont->pfont == pfont)
188623a0898aSmrg		    fprintf (stderr, "closing font which hasn't been opened\n");
188723a0898aSmrg	    }
188823a0898aSmrg	}
188923a0898aSmrg    }
189023a0898aSmrg#endif
189123a0898aSmrg    (*pfont->unload_font) (pfont);
189223a0898aSmrg}
189323a0898aSmrg
189423a0898aSmrgstatic int
189523a0898aSmrgfs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
189623a0898aSmrg{
189723a0898aSmrg    FSBlockedGlyphPtr	    bglyph = (FSBlockedGlyphPtr) blockrec->data;
189823a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
189923a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
190023a0898aSmrg    FontPtr		    pfont = bglyph->pfont;
190123a0898aSmrg					/* works for either blocked font
190223a0898aSmrg					   or glyph rec...  pfont is at
190323a0898aSmrg					   the very beginning of both
190423a0898aSmrg					   blockrec->data structures */
190523a0898aSmrg    FSFontDataPtr	    fsd = (FSFontDataPtr) (pfont->fpePrivate);
190623a0898aSmrg    FSFontPtr		    fsdata = (FSFontPtr) pfont->fontPrivate;
190723a0898aSmrg    FontInfoPtr		    pfi = &pfont->info;
190823a0898aSmrg    fsQueryXBitmaps16Reply  *rep;
190923a0898aSmrg    char		    *buf;
19107673729aSmrg    long		    bufleft; /* length of reply left to use */
191123a0898aSmrg    fsOffset32		    *ppbits;
191223a0898aSmrg    fsOffset32		    local_off;
191323a0898aSmrg    char		    *off_adr;
191423a0898aSmrg    pointer		    pbitmaps;
191523a0898aSmrg    char		    *bits, *allbits;
191623a0898aSmrg#ifdef DEBUG
191723a0898aSmrg    char		    *origallbits;
191823a0898aSmrg#endif
191923a0898aSmrg    int			    i,
192023a0898aSmrg			    err;
192123a0898aSmrg    int			    nranges = 0;
192223a0898aSmrg    int			    ret;
192323a0898aSmrg    fsRange		    *nextrange = 0;
192423a0898aSmrg    unsigned long	    minchar, maxchar;
192523a0898aSmrg
192623a0898aSmrg    rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
19279d21a897Sspz    if (!rep || rep->type == FS_Error ||
19287673729aSmrg	(rep->length < LENGTHOF(fsQueryXBitmaps16Reply)))
192923a0898aSmrg    {
193023a0898aSmrg	if (ret == FSIO_BLOCK)
193123a0898aSmrg	    return StillWorking;
193223a0898aSmrg	if (rep)
193323a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
193423a0898aSmrg	err = AllocError;
19359d21a897Sspz	_fs_reply_failed (rep, fsQueryXBitmaps16Reply, "<");
193623a0898aSmrg	goto bail;
193723a0898aSmrg    }
193823a0898aSmrg
193923a0898aSmrg    buf = (char *) rep;
194023a0898aSmrg    buf += SIZEOF (fsQueryXBitmaps16Reply);
194123a0898aSmrg
19429d21a897Sspz    bufleft = rep->length << 2;
19439d21a897Sspz    bufleft -= SIZEOF (fsQueryXBitmaps16Reply);
19449d21a897Sspz
19459d21a897Sspz    if ((bufleft / SIZEOF (fsOffset32)) < rep->num_chars)
19469d21a897Sspz    {
19479d21a897Sspz#ifdef DEBUG
19487673729aSmrg	fprintf(stderr,
19497673729aSmrg		"fsQueryXBitmaps16: num_chars (%d) > bufleft (%ld) / %d\n",
19507673729aSmrg		rep->num_chars, bufleft, SIZEOF (fsOffset32));
19519d21a897Sspz#endif
19527673729aSmrg	err = AllocError;
19537673729aSmrg	goto bail;
19549d21a897Sspz    }
195523a0898aSmrg    ppbits = (fsOffset32 *) buf;
195623a0898aSmrg    buf += SIZEOF (fsOffset32) * (rep->num_chars);
19579d21a897Sspz    bufleft -= SIZEOF (fsOffset32) * (rep->num_chars);
19589d21a897Sspz
19597673729aSmrg#if 0
19609d21a897Sspz    if (bufleft < rep->nbytes)
19619d21a897Sspz    {
19629d21a897Sspz#ifdef DEBUG
19639d21a897Sspz        fprintf(stderr,
19649d21a897Sspz                "fsQueryXBitmaps16: nbytes (%d) > bufleft (%ld)\n",
19659d21a897Sspz                rep->nbytes, bufleft);
19669d21a897Sspz#endif
19679d21a897Sspz        err = AllocError;
19689d21a897Sspz        goto bail;
19699d21a897Sspz    }
19707673729aSmrg#endif
197123a0898aSmrg
19727673729aSmrg    if (bufleft < rep->nbytes)
19737673729aSmrg    {
19747673729aSmrg#ifdef DEBUG
19757673729aSmrg	fprintf(stderr,
19767673729aSmrg		"fsQueryXBitmaps16: nbytes (%d) > bufleft (%ld)\n",
19777673729aSmrg		rep->nbytes, bufleft);
19787673729aSmrg#endif
19797673729aSmrg	err = AllocError;
19807673729aSmrg	goto bail;
19817673729aSmrg    }
198223a0898aSmrg    pbitmaps = (pointer ) buf;
198323a0898aSmrg
198423a0898aSmrg    if (blockrec->type == FS_LOAD_GLYPHS)
198523a0898aSmrg    {
198623a0898aSmrg	nranges = bglyph->num_expected_ranges;
198723a0898aSmrg	nextrange = bglyph->expected_ranges;
198823a0898aSmrg    }
198923a0898aSmrg
199023a0898aSmrg    /* place the incoming glyphs */
199123a0898aSmrg    if (nranges)
199223a0898aSmrg    {
199323a0898aSmrg	/* We're operating under the assumption that the ranges
199423a0898aSmrg	   requested in the LoadGlyphs call were all legal for this
199523a0898aSmrg	   font, and that individual ranges do not cover multiple
199623a0898aSmrg	   rows...  fs_build_range() is designed to ensure this. */
199723a0898aSmrg	minchar = (nextrange->min_char_high - pfi->firstRow) *
199823a0898aSmrg		  (pfi->lastCol - pfi->firstCol + 1) +
199923a0898aSmrg		  nextrange->min_char_low - pfi->firstCol;
200023a0898aSmrg	maxchar = (nextrange->max_char_high - pfi->firstRow) *
200123a0898aSmrg		  (pfi->lastCol - pfi->firstCol + 1) +
200223a0898aSmrg		  nextrange->max_char_low - pfi->firstCol;
200323a0898aSmrg	nextrange++;
200423a0898aSmrg    }
200523a0898aSmrg    else
200623a0898aSmrg    {
200723a0898aSmrg	minchar = 0;
200823a0898aSmrg	maxchar = rep->num_chars;
200923a0898aSmrg    }
201023a0898aSmrg
201123a0898aSmrg    off_adr = (char *)ppbits;
201241c30155Smrg
201323a0898aSmrg    allbits = fs_alloc_glyphs (pfont, rep->nbytes);
201441c30155Smrg
201523a0898aSmrg    if (!allbits)
201623a0898aSmrg    {
201723a0898aSmrg	err = AllocError;
201823a0898aSmrg	goto bail;
201923a0898aSmrg    }
202041c30155Smrg
202123a0898aSmrg#ifdef DEBUG
202223a0898aSmrg    origallbits = allbits;
202323a0898aSmrg    fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
202423a0898aSmrg	     (int) rep->num_chars, (int) rep->nbytes, fsd->name);
202523a0898aSmrg#endif
202641c30155Smrg
202723a0898aSmrg    for (i = 0; i < rep->num_chars; i++)
202823a0898aSmrg    {
202923a0898aSmrg	memcpy(&local_off, off_adr, SIZEOF(fsOffset32));	/* align it */
203023a0898aSmrg	if (blockrec->type == FS_OPEN_FONT ||
203123a0898aSmrg	    fsdata->encoding[minchar].bits == &_fs_glyph_requested)
203223a0898aSmrg	{
203323a0898aSmrg	    /*
203423a0898aSmrg	     * Broken X font server returns bits for missing characters
203523a0898aSmrg	     * when font is padded
203623a0898aSmrg	     */
203723a0898aSmrg	    if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
203823a0898aSmrg	    {
20399d21a897Sspz		if (local_off.length &&
20407673729aSmrg		    (local_off.position < rep->nbytes) &&
20417673729aSmrg		    (local_off.length <= (rep->nbytes - local_off.position)))
204223a0898aSmrg		{
204323a0898aSmrg		    bits = allbits;
204423a0898aSmrg		    allbits += local_off.length;
204523a0898aSmrg		    memcpy(bits, (char *)pbitmaps + local_off.position,
204623a0898aSmrg			   local_off.length);
204723a0898aSmrg		}
204823a0898aSmrg		else
204923a0898aSmrg		    bits = &_fs_glyph_zero_length;
205023a0898aSmrg	    }
205123a0898aSmrg	    else
205223a0898aSmrg		bits = 0;
205323a0898aSmrg	    if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
205423a0898aSmrg		fsd->glyphs_to_get--;
205523a0898aSmrg	    fsdata->encoding[minchar].bits = bits;
205623a0898aSmrg	}
205723a0898aSmrg	if (minchar++ == maxchar)
205823a0898aSmrg	{
205923a0898aSmrg	    if (!--nranges) break;
206023a0898aSmrg	    minchar = (nextrange->min_char_high - pfi->firstRow) *
206123a0898aSmrg		      (pfi->lastCol - pfi->firstCol + 1) +
206223a0898aSmrg		      nextrange->min_char_low - pfi->firstCol;
206323a0898aSmrg	    maxchar = (nextrange->max_char_high - pfi->firstRow) *
206423a0898aSmrg		      (pfi->lastCol - pfi->firstCol + 1) +
206523a0898aSmrg		      nextrange->max_char_low - pfi->firstCol;
206623a0898aSmrg	    nextrange++;
206723a0898aSmrg	}
206823a0898aSmrg	off_adr += SIZEOF(fsOffset32);
206923a0898aSmrg    }
207023a0898aSmrg#ifdef DEBUG
207123a0898aSmrg    fprintf (stderr, "Used %d bytes instead of %d\n",
207223a0898aSmrg	     (int) (allbits - origallbits), (int) rep->nbytes);
207323a0898aSmrg#endif
207423a0898aSmrg
207523a0898aSmrg    if (blockrec->type == FS_OPEN_FONT)
207623a0898aSmrg    {
207723a0898aSmrg	fsd->glyphs_to_get = 0;
207823a0898aSmrg	bfont->state = FS_DONE_REPLY;
207923a0898aSmrg    }
208023a0898aSmrg    err = Successful;
208123a0898aSmrg
208223a0898aSmrgbail:
208323a0898aSmrg    _fs_done_read (conn, rep->length << 2);
208423a0898aSmrg    return err;
208523a0898aSmrg}
208623a0898aSmrg
208723a0898aSmrgstatic int
208841c30155Smrgfs_send_load_glyphs(pointer client, FontPtr pfont,
208923a0898aSmrg		    int nranges, fsRange *ranges)
209023a0898aSmrg{
209123a0898aSmrg    FontPathElementPtr	    fpe = pfont->fpe;
209223a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
209323a0898aSmrg    FSBlockedGlyphPtr	    blockedglyph;
209423a0898aSmrg    fsQueryXBitmaps16Req    req;
209523a0898aSmrg    FSBlockDataPtr	    blockrec;
209623a0898aSmrg
209723a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
209823a0898aSmrg	return BadCharRange;
209941c30155Smrg
210023a0898aSmrg    /* make a new block record, and add it to the end of the list */
210123a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
210223a0898aSmrg    if (!blockrec)
210323a0898aSmrg	return AllocError;
210423a0898aSmrg    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
210523a0898aSmrg    blockedglyph->pfont = pfont;
210623a0898aSmrg    blockedglyph->num_expected_ranges = nranges;
210723a0898aSmrg    /* Assumption: it's our job to free ranges */
210823a0898aSmrg    blockedglyph->expected_ranges = ranges;
210923a0898aSmrg    blockedglyph->clients_depending = (FSClientsDependingPtr)0;
211023a0898aSmrg
211123a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
211223a0898aSmrg    {
211323a0898aSmrg	_fs_pending_reply (conn);
211423a0898aSmrg	return Suspended;
211523a0898aSmrg    }
211641c30155Smrg
211723a0898aSmrg    /* send the request */
211823a0898aSmrg    req.reqType = FS_QueryXBitmaps16;
211923a0898aSmrg    req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
212023a0898aSmrg    req.format = pfont->format;
212123a0898aSmrg    if (pfont->info.terminalFont)
212223a0898aSmrg	req.format = (req.format & ~(BitmapFormatImageRectMask)) |
212323a0898aSmrg		     BitmapFormatImageRectMax;
212423a0898aSmrg    req.range = TRUE;
212523a0898aSmrg    /* each range takes up 4 bytes */
212623a0898aSmrg    req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
212723a0898aSmrg    req.num_ranges = nranges * 2;	/* protocol wants count of fsChar2bs */
212823a0898aSmrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
212923a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
213023a0898aSmrg
213123a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
213241c30155Smrg
213323a0898aSmrg    /* Send ranges to the server... pack into a char array by hand
213423a0898aSmrg       to avoid structure-packing portability problems and to
213523a0898aSmrg       handle swapping for version1 protocol */
213623a0898aSmrg    if (nranges)
213723a0898aSmrg    {
213823a0898aSmrg#define RANGE_BUFFER_SIZE 64
213923a0898aSmrg#define RANGE_BUFFER_SIZE_MASK 63
214023a0898aSmrg	int i;
214123a0898aSmrg	char range_buffer[RANGE_BUFFER_SIZE * 4];
214223a0898aSmrg	char *range_buffer_p;
214323a0898aSmrg
214423a0898aSmrg	range_buffer_p = range_buffer;
214523a0898aSmrg	for (i = 0; i < nranges;)
214623a0898aSmrg	{
214723a0898aSmrg	    if (conn->fsMajorVersion > 1)
214823a0898aSmrg	    {
214923a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_high;
215023a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_low;
215123a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_high;
215223a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_low;
215323a0898aSmrg	    }
215423a0898aSmrg	    else
215523a0898aSmrg	    {
215623a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_low;
215723a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_high;
215823a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_low;
215923a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_high;
216023a0898aSmrg	    }
216123a0898aSmrg
216223a0898aSmrg	    if (!(++i & RANGE_BUFFER_SIZE_MASK))
216323a0898aSmrg	    {
216423a0898aSmrg		_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
216523a0898aSmrg		range_buffer_p = range_buffer;
216623a0898aSmrg	    }
216723a0898aSmrg	}
216823a0898aSmrg	if (i &= RANGE_BUFFER_SIZE_MASK)
216923a0898aSmrg	    _fs_write(conn, range_buffer, i * 4);
217023a0898aSmrg    }
217123a0898aSmrg
217223a0898aSmrg    _fs_prepare_for_reply (conn);
217323a0898aSmrg    return Suspended;
217423a0898aSmrg}
217523a0898aSmrg
217623a0898aSmrg
217723a0898aSmrgextern pointer serverClient;	/* This could be any number that
217823a0898aSmrg				   doesn't conflict with existing
217923a0898aSmrg				   client values. */
218023a0898aSmrg
218123a0898aSmrgstatic int
218241c30155Smrg_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
218323a0898aSmrg		unsigned int nchars, int item_size, unsigned char *data)
218423a0898aSmrg{
218523a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) pfont->fpe->private;
218623a0898aSmrg    int			    nranges = 0;
218723a0898aSmrg    fsRange		    *ranges = NULL;
218823a0898aSmrg    int			    res;
218923a0898aSmrg    FSBlockDataPtr	    blockrec;
219023a0898aSmrg    FSBlockedGlyphPtr	    blockedglyph;
219123a0898aSmrg    FSClientsDependingPtr   *clients_depending = NULL;
219223a0898aSmrg    int			    err;
219323a0898aSmrg
219423a0898aSmrg    /* see if the result is already there */
219523a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
219623a0898aSmrg    {
219723a0898aSmrg	if (blockrec->type == FS_LOAD_GLYPHS)
219823a0898aSmrg	{
219923a0898aSmrg	    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
220023a0898aSmrg	    if (blockedglyph->pfont == pfont)
220123a0898aSmrg	    {
220223a0898aSmrg		/* Look for this request */
220323a0898aSmrg		if (blockrec->client == client)
220423a0898aSmrg		{
220523a0898aSmrg		    err = blockrec->errcode;
220623a0898aSmrg		    if (err == StillWorking)
220723a0898aSmrg			return Suspended;
220823a0898aSmrg		    _fs_signal_clients_depending(&blockedglyph->clients_depending);
220923a0898aSmrg		    _fs_remove_block_rec(conn, blockrec);
221023a0898aSmrg		    return err;
221123a0898aSmrg		}
221223a0898aSmrg		/* We've found an existing LoadGlyphs blockrec for this
221323a0898aSmrg		   font but for another client.  Rather than build a
221423a0898aSmrg		   blockrec for it now (which entails some complex
221523a0898aSmrg		   maintenance), we'll add it to a queue of clients to
221623a0898aSmrg		   be signalled when the existing LoadGlyphs is
221723a0898aSmrg		   completed.  */
221823a0898aSmrg		clients_depending = &blockedglyph->clients_depending;
221923a0898aSmrg		break;
222023a0898aSmrg	    }
222123a0898aSmrg	}
222223a0898aSmrg	else if (blockrec->type == FS_OPEN_FONT)
222323a0898aSmrg	{
222423a0898aSmrg	    FSBlockedFontPtr bfont;
222523a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
222623a0898aSmrg	    if (bfont->pfont == pfont)
222723a0898aSmrg	    {
222823a0898aSmrg		/*
222923a0898aSmrg		 * An OpenFont is pending for this font, this must
223023a0898aSmrg		 * be from a reopen attempt, so finish the open
223123a0898aSmrg		 * attempt and retry the LoadGlyphs
223223a0898aSmrg		 */
223323a0898aSmrg		if (blockrec->client == client)
223423a0898aSmrg		{
223523a0898aSmrg		    err = blockrec->errcode;
223623a0898aSmrg		    if (err == StillWorking)
223723a0898aSmrg			return Suspended;
223841c30155Smrg
223923a0898aSmrg		    _fs_signal_clients_depending(&bfont->clients_depending);
224023a0898aSmrg		    _fs_remove_block_rec(conn, blockrec);
224123a0898aSmrg		    if (err != Successful)
224223a0898aSmrg			return err;
224323a0898aSmrg		    break;
224423a0898aSmrg		}
224523a0898aSmrg		/* We've found an existing OpenFont blockrec for this
224623a0898aSmrg		   font but for another client.  Rather than build a
224723a0898aSmrg		   blockrec for it now (which entails some complex
224823a0898aSmrg		   maintenance), we'll add it to a queue of clients to
224923a0898aSmrg		   be signalled when the existing OpenFont is
225023a0898aSmrg		   completed.  */
225123a0898aSmrg		if (blockrec->errcode == StillWorking)
225223a0898aSmrg		{
225323a0898aSmrg		    clients_depending = &bfont->clients_depending;
225423a0898aSmrg		    break;
225523a0898aSmrg		}
225623a0898aSmrg	    }
225723a0898aSmrg	}
225823a0898aSmrg    }
225923a0898aSmrg
226023a0898aSmrg    /*
226123a0898aSmrg     * see if the desired glyphs already exist, and return Successful if they
226223a0898aSmrg     * do, otherwise build up character range/character string
226323a0898aSmrg     */
226423a0898aSmrg    res = fs_build_range(pfont, range_flag, nchars, item_size, data,
226523a0898aSmrg			 &nranges, &ranges);
226623a0898aSmrg
226723a0898aSmrg    switch (res)
226823a0898aSmrg    {
226923a0898aSmrg	case AccessDone:
227023a0898aSmrg	    return Successful;
227123a0898aSmrg
227223a0898aSmrg	case Successful:
227323a0898aSmrg	    break;
227423a0898aSmrg
227523a0898aSmrg	default:
227623a0898aSmrg	    return res;
227723a0898aSmrg    }
227823a0898aSmrg
227923a0898aSmrg    /*
228023a0898aSmrg     * If clients_depending is not null, this request must wait for
228123a0898aSmrg     * some prior request(s) to complete.
228223a0898aSmrg     */
228323a0898aSmrg    if (clients_depending)
228423a0898aSmrg    {
228523a0898aSmrg	/* Since we're not ready to send the load_glyphs request yet,
228623a0898aSmrg	   clean up the damage (if any) caused by the fs_build_range()
228723a0898aSmrg	   call. */
228823a0898aSmrg	if (nranges)
228923a0898aSmrg	{
229023a0898aSmrg	    _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
22917f7f5e4eSmrg	    free(ranges);
229223a0898aSmrg	}
229323a0898aSmrg	return _fs_add_clients_depending(clients_depending, client);
229423a0898aSmrg    }
229523a0898aSmrg
229623a0898aSmrg    /*
229723a0898aSmrg     * If fsd->generation != conn->generation, the font has been closed
229823a0898aSmrg     * due to a lost connection.  We will reopen it, which will result
229923a0898aSmrg     * in one of three things happening:
230023a0898aSmrg     *	 1) The open will succeed and obtain the same font.  Life
230123a0898aSmrg     *	    is wonderful.
230223a0898aSmrg     *	 2) The open will fail.  There is code above to recognize this
230323a0898aSmrg     *	    and flunk the LoadGlyphs request.  The client might not be
230423a0898aSmrg     *	    thrilled.
230523a0898aSmrg     *	 3) Worst case: the open will succeed but the font we open will
230623a0898aSmrg     *	    be different.  The fs_read_query_info() procedure attempts
230723a0898aSmrg     *	    to detect this by comparing the existing metrics and
230823a0898aSmrg     *	    properties against those of the reopened font... if they
230923a0898aSmrg     *	    don't match, we flunk the reopen, which eventually results
231023a0898aSmrg     *	    in flunking the LoadGlyphs request.  We could go a step
231123a0898aSmrg     *	    further and compare the extents, but this should be
231223a0898aSmrg     *	    sufficient.
231323a0898aSmrg     */
231423a0898aSmrg    if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
231523a0898aSmrg    {
231623a0898aSmrg	/* Since we're not ready to send the load_glyphs request yet,
231723a0898aSmrg	   clean up the damage caused by the fs_build_range() call. */
231823a0898aSmrg	_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
23197f7f5e4eSmrg	free(ranges);
232023a0898aSmrg
232123a0898aSmrg	/* Now try to reopen the font. */
232223a0898aSmrg	return fs_send_open_font(client, pfont->fpe,
232323a0898aSmrg				 (Mask)FontReopen, (char *)0, 0,
232423a0898aSmrg				 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
232523a0898aSmrg				 (XID)0, &pfont);
232623a0898aSmrg    }
232723a0898aSmrg
232823a0898aSmrg    return fs_send_load_glyphs(client, pfont, nranges, ranges);
232923a0898aSmrg}
233023a0898aSmrg
233123a0898aSmrgint
233223a0898aSmrgfs_load_all_glyphs(FontPtr pfont)
233323a0898aSmrg{
233423a0898aSmrg    int		err;
233523a0898aSmrg    FSFpePtr	conn = (FSFpePtr) pfont->fpe->private;
233623a0898aSmrg
233723a0898aSmrg    /*
233823a0898aSmrg     * The purpose of this procedure is to load all glyphs in the event
233923a0898aSmrg     * that we're dealing with someone who doesn't understand the finer
234023a0898aSmrg     * points of glyph caching...  it is called from _fs_get_glyphs() if
234123a0898aSmrg     * the latter is called to get glyphs that have not yet been loaded.
234223a0898aSmrg     * We assume that the caller will not know how to handle a return
234323a0898aSmrg     * value of Suspended (usually the case for a GetGlyphs() caller),
234423a0898aSmrg     * so this procedure hangs around, freezing the server, for the
234523a0898aSmrg     * request to complete.  This is an unpleasant kluge called to
234623a0898aSmrg     * perform an unpleasant job that, we hope, will never be required.
234723a0898aSmrg     */
234823a0898aSmrg
234923a0898aSmrg    while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) ==
235023a0898aSmrg	   Suspended)
235123a0898aSmrg    {
235223a0898aSmrg	if (fs_await_reply (conn) != FSIO_READY)
235323a0898aSmrg	{
235423a0898aSmrg	    /* Get rid of blockrec */
235523a0898aSmrg	    fs_client_died(serverClient, pfont->fpe);
235623a0898aSmrg	    err = BadCharRange;
235723a0898aSmrg	    break;
235823a0898aSmrg	}
235923a0898aSmrg	fs_read_reply (pfont->fpe, serverClient);
236023a0898aSmrg    }
236123a0898aSmrg    return err;
236223a0898aSmrg}
236323a0898aSmrg
236423a0898aSmrgstatic int
236523a0898aSmrgfs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
236623a0898aSmrg{
236723a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
236823a0898aSmrg    FSBlockedListPtr	blist = (FSBlockedListPtr) blockrec->data;
236923a0898aSmrg    fsListFontsReply	*rep;
237023a0898aSmrg    char		*data;
23717673729aSmrg    long		dataleft; /* length of reply left to use */
237223a0898aSmrg    int			length,
237323a0898aSmrg			i,
237423a0898aSmrg			ret;
237523a0898aSmrg    int			err;
237623a0898aSmrg
237723a0898aSmrg    rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
23789d21a897Sspz    if (!rep || rep->type == FS_Error ||
23797673729aSmrg	(rep->length < LENGTHOF(fsListFontsReply)))
238023a0898aSmrg    {
238123a0898aSmrg	if (ret == FSIO_BLOCK)
238223a0898aSmrg	    return StillWorking;
238323a0898aSmrg	if (rep)
238423a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
23859d21a897Sspz	_fs_reply_failed (rep, fsListFontsReply, "<");
238623a0898aSmrg	return AllocError;
238723a0898aSmrg    }
238823a0898aSmrg    data = (char *) rep + SIZEOF (fsListFontsReply);
23899d21a897Sspz    dataleft = (rep->length << 2) - SIZEOF (fsListFontsReply);
239023a0898aSmrg
239123a0898aSmrg    err = Successful;
239223a0898aSmrg    /* copy data into FontPathRecord */
239341c30155Smrg    for (i = 0; i < rep->nFonts; i++)
239423a0898aSmrg    {
23957673729aSmrg	if (dataleft < 1)
23967673729aSmrg	    break;
239723a0898aSmrg	length = *(unsigned char *)data++;
23987673729aSmrg	dataleft--; /* used length byte */
23997673729aSmrg	if (length > dataleft) {
24009d21a897Sspz#ifdef DEBUG
24017673729aSmrg	    fprintf(stderr,
24027673729aSmrg		    "fsListFonts: name length (%d) > dataleft (%ld)\n",
24037673729aSmrg		    length, dataleft);
24049d21a897Sspz#endif
24057673729aSmrg	    err = BadFontName;
24067673729aSmrg	    break;
24077673729aSmrg	}
240823a0898aSmrg	err = AddFontNamesName(blist->names, data, length);
240923a0898aSmrg	if (err != Successful)
241023a0898aSmrg	    break;
241123a0898aSmrg	data += length;
24129d21a897Sspz	dataleft -= length;
241323a0898aSmrg    }
241423a0898aSmrg    _fs_done_read (conn, rep->length << 2);
241523a0898aSmrg    return err;
241623a0898aSmrg}
241723a0898aSmrg
241823a0898aSmrgstatic int
241941c30155Smrgfs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern,
242023a0898aSmrg		   int patlen, int maxnames, FontNamesPtr newnames)
242123a0898aSmrg{
242223a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
242323a0898aSmrg    FSBlockDataPtr	blockrec;
242423a0898aSmrg    FSBlockedListPtr	blockedlist;
242523a0898aSmrg    fsListFontsReq	req;
242623a0898aSmrg
242723a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
242823a0898aSmrg	return BadFontName;
242941c30155Smrg
243023a0898aSmrg    /* make a new block record, and add it to the end of the list */
243123a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
243223a0898aSmrg    if (!blockrec)
243323a0898aSmrg	return AllocError;
243423a0898aSmrg    blockedlist = (FSBlockedListPtr) blockrec->data;
243523a0898aSmrg    blockedlist->names = newnames;
243623a0898aSmrg
243723a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
243823a0898aSmrg    {
243923a0898aSmrg	_fs_pending_reply (conn);
244023a0898aSmrg	return Suspended;
244123a0898aSmrg    }
244241c30155Smrg
244323a0898aSmrg    _fs_client_access (conn, client, FALSE);
244423a0898aSmrg    _fs_client_resolution(conn);
244523a0898aSmrg
244623a0898aSmrg    /* send the request */
244723a0898aSmrg    req.reqType = FS_ListFonts;
24487f7f5e4eSmrg    req.pad = 0;
244923a0898aSmrg    req.maxNames = maxnames;
245023a0898aSmrg    req.nbytes = patlen;
245123a0898aSmrg    req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
245223a0898aSmrg    _fs_add_req_log(conn, FS_ListFonts);
245323a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
245423a0898aSmrg    _fs_write_pad(conn, (char *) pattern, patlen);
245523a0898aSmrg
245623a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
245741c30155Smrg
245823a0898aSmrg#ifdef NCD
245923a0898aSmrg    if (configData.ExtendedFontDiags) {
246023a0898aSmrg	char        buf[256];
246123a0898aSmrg
246223a0898aSmrg	memcpy(buf, pattern, MIN(256, patlen));
246323a0898aSmrg	buf[MIN(256, patlen)] = '\0';
246423a0898aSmrg	printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
246523a0898aSmrg	       buf, fpe->name);
246623a0898aSmrg    }
246723a0898aSmrg#endif
246823a0898aSmrg
246923a0898aSmrg    _fs_prepare_for_reply (conn);
247023a0898aSmrg    return Suspended;
247123a0898aSmrg}
247223a0898aSmrg
247323a0898aSmrgstatic int
247441c30155Smrgfs_list_fonts(pointer client, FontPathElementPtr fpe,
247523a0898aSmrg	      char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
247623a0898aSmrg{
247723a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
247823a0898aSmrg    FSBlockDataPtr	blockrec;
247923a0898aSmrg    int			err;
248023a0898aSmrg
248123a0898aSmrg    /* see if the result is already there */
248223a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
248323a0898aSmrg    {
248441c30155Smrg	if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
248523a0898aSmrg	{
248623a0898aSmrg	    err = blockrec->errcode;
248723a0898aSmrg	    if (err == StillWorking)
248823a0898aSmrg		return Suspended;
248923a0898aSmrg	    _fs_remove_block_rec(conn, blockrec);
249023a0898aSmrg	    return err;
249123a0898aSmrg	}
249223a0898aSmrg    }
249323a0898aSmrg
249423a0898aSmrg    /* didn't find waiting record, so send a new one */
249523a0898aSmrg    return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
249623a0898aSmrg}
249723a0898aSmrg
249823a0898aSmrg/*
249923a0898aSmrg * Read a single list info reply and restart for the next reply
250023a0898aSmrg */
250123a0898aSmrgstatic int
250223a0898aSmrgfs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
250323a0898aSmrg{
250423a0898aSmrg    FSBlockedListInfoPtr	binfo = (FSBlockedListInfoPtr) blockrec->data;
250523a0898aSmrg    fsListFontsWithXInfoReply	*rep;
250623a0898aSmrg    char			*buf;
25077673729aSmrg    long			bufleft;
250823a0898aSmrg    FSFpePtr			conn = (FSFpePtr) fpe->private;
250923a0898aSmrg    fsPropInfo			*pi;
251023a0898aSmrg    fsPropOffset		*po;
251123a0898aSmrg    pointer			pd;
251223a0898aSmrg    int				ret;
251323a0898aSmrg    int				err;
251423a0898aSmrg
251523a0898aSmrg    /* clean up anything from the last trip */
251623a0898aSmrg    _fs_free_props (&binfo->info);
251723a0898aSmrg
251823a0898aSmrg    rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
25199d21a897Sspz    if (!rep || rep->type == FS_Error ||
25207673729aSmrg	((rep->nameLength != 0) &&
25217673729aSmrg	 (rep->length < LENGTHOF(fsListFontsWithXInfoReply))))
252223a0898aSmrg    {
252323a0898aSmrg	if (ret == FSIO_BLOCK)
252423a0898aSmrg	    return StillWorking;
252523a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
252623a0898aSmrg	err = AllocError;
25277673729aSmrg	_fs_reply_failed (rep, fsListFontsWithXInfoReply, "<");
252823a0898aSmrg	goto done;
252923a0898aSmrg    }
253023a0898aSmrg    /*
253123a0898aSmrg     * Normal termination -- the list ends with a name of length 0
253223a0898aSmrg     */
253323a0898aSmrg    if (rep->nameLength == 0)
253423a0898aSmrg    {
253523a0898aSmrg#ifdef DEBUG
253623a0898aSmrg	fprintf (stderr, "fs_read_list_info done\n");
253723a0898aSmrg#endif
253823a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
253923a0898aSmrg	err = BadFontName;
254023a0898aSmrg	goto done;
254123a0898aSmrg    }
254223a0898aSmrg
254323a0898aSmrg    buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
25447673729aSmrg    bufleft = (rep->length << 2) - SIZEOF (fsListFontsWithXInfoReply);
254541c30155Smrg
254623a0898aSmrg    /*
254723a0898aSmrg     * The original FS implementation didn't match
254823a0898aSmrg     * the spec, version 1 was respecified to match the FS.
254923a0898aSmrg     * Version 2 matches the original intent
255023a0898aSmrg     */
255123a0898aSmrg    if (conn->fsMajorVersion <= 1)
255223a0898aSmrg    {
25537673729aSmrg	if (rep->nameLength > bufleft) {
25547673729aSmrg#ifdef DEBUG
25557673729aSmrg	    fprintf(stderr,
25567673729aSmrg		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
25577673729aSmrg		    (int) rep->nameLength, bufleft);
25587673729aSmrg#endif
25597673729aSmrg	    err = AllocError;
25607673729aSmrg	    goto done;
25617673729aSmrg	}
25627673729aSmrg	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
256323a0898aSmrg	memcpy (binfo->name, buf, rep->nameLength);
256423a0898aSmrg	buf += _fs_pad_length (rep->nameLength);
25657673729aSmrg	bufleft -= _fs_pad_length (rep->nameLength);
256623a0898aSmrg    }
256723a0898aSmrg    pi = (fsPropInfo *) buf;
25687673729aSmrg    if (SIZEOF (fsPropInfo) > bufleft) {
25697673729aSmrg#ifdef DEBUG
25707673729aSmrg	fprintf(stderr,
25717673729aSmrg		"fsListFontsWithXInfo: PropInfo length (%d) > bufleft (%ld)\n",
25727673729aSmrg		(int) SIZEOF (fsPropInfo), bufleft);
25737673729aSmrg#endif
25747673729aSmrg	err = AllocError;
25757673729aSmrg	goto done;
25767673729aSmrg    }
25777673729aSmrg    bufleft -= SIZEOF (fsPropInfo);
257823a0898aSmrg    buf += SIZEOF (fsPropInfo);
257923a0898aSmrg    po = (fsPropOffset *) buf;
25807673729aSmrg    if (pi->num_offsets > (bufleft / SIZEOF (fsPropOffset))) {
25817673729aSmrg#ifdef DEBUG
25827673729aSmrg	fprintf(stderr,
25837673729aSmrg		"fsListFontsWithXInfo: offset length (%d * %d) > bufleft (%ld)\n",
25847673729aSmrg		pi->num_offsets, (int) SIZEOF (fsPropOffset), bufleft);
25857673729aSmrg#endif
25867673729aSmrg	err = AllocError;
25877673729aSmrg	goto done;
25887673729aSmrg    }
25897673729aSmrg    bufleft -= pi->num_offsets * SIZEOF (fsPropOffset);
259023a0898aSmrg    buf += pi->num_offsets * SIZEOF (fsPropOffset);
259123a0898aSmrg    pd = (pointer) buf;
25927673729aSmrg    if (pi->data_len > bufleft) {
25937673729aSmrg#ifdef DEBUG
25947673729aSmrg	fprintf(stderr,
25957673729aSmrg		"fsListFontsWithXInfo: data length (%d) > bufleft (%ld)\n",
25967673729aSmrg		pi->data_len, bufleft);
25977673729aSmrg#endif
25987673729aSmrg	err = AllocError;
25997673729aSmrg	goto done;
26007673729aSmrg    }
26017673729aSmrg    bufleft -= pi->data_len;
260223a0898aSmrg    buf += pi->data_len;
260323a0898aSmrg    if (conn->fsMajorVersion > 1)
260423a0898aSmrg    {
26057673729aSmrg	if (rep->nameLength > bufleft) {
26067673729aSmrg#ifdef DEBUG
26077673729aSmrg	    fprintf(stderr,
26087673729aSmrg		    "fsListFontsWithXInfo: name length (%d) > bufleft (%ld)\n",
26097673729aSmrg		    (int) rep->nameLength, bufleft);
26107673729aSmrg#endif
26117673729aSmrg	    err = AllocError;
26127673729aSmrg	    goto done;
26137673729aSmrg	}
26147673729aSmrg	/* binfo->name is a 256 char array, rep->nameLength is a CARD8 */
261523a0898aSmrg	memcpy (binfo->name, buf, rep->nameLength);
261623a0898aSmrg	buf += _fs_pad_length (rep->nameLength);
26177673729aSmrg	bufleft -= _fs_pad_length (rep->nameLength);
261823a0898aSmrg    }
261923a0898aSmrg
262023a0898aSmrg#ifdef DEBUG
262123a0898aSmrg    binfo->name[rep->nameLength] = '\0';
262223a0898aSmrg    fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
262323a0898aSmrg#endif
262423a0898aSmrg    err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
262523a0898aSmrg    if (err != Successful)
262623a0898aSmrg    {
262723a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
262823a0898aSmrg	goto done;
262923a0898aSmrg    }
263023a0898aSmrg    binfo->namelen = rep->nameLength;
263123a0898aSmrg    binfo->remaining = rep->nReplies;
263223a0898aSmrg
263323a0898aSmrg    binfo->status = FS_LFWI_REPLY;
263441c30155Smrg
263523a0898aSmrg    /* disable this font server until we've processed this response */
263623a0898aSmrg    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
263723a0898aSmrg    FD_CLR(conn->fs_fd, &_fs_fd_mask);
263841c30155Smrgdone:
263923a0898aSmrg    _fs_done_read (conn, rep->length << 2);
264023a0898aSmrg    return err;
264123a0898aSmrg}
264223a0898aSmrg
264323a0898aSmrg/* ARGSUSED */
264423a0898aSmrgstatic int
264541c30155Smrgfs_start_list_with_info(pointer client, FontPathElementPtr fpe,
264623a0898aSmrg			char *pattern, int len, int maxnames, pointer *pdata)
264723a0898aSmrg{
264823a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
264923a0898aSmrg    FSBlockDataPtr	    blockrec;
265023a0898aSmrg    FSBlockedListInfoPtr    binfo;
265123a0898aSmrg    fsListFontsWithXInfoReq req;
265223a0898aSmrg
265323a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
265423a0898aSmrg	return BadFontName;
265523a0898aSmrg
265623a0898aSmrg    /* make a new block record, and add it to the end of the list */
265723a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
265823a0898aSmrg    if (!blockrec)
265923a0898aSmrg	return AllocError;
266041c30155Smrg
266123a0898aSmrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
266223a0898aSmrg    bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
266323a0898aSmrg    binfo->status = FS_LFWI_WAITING;
266423a0898aSmrg
266523a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
266623a0898aSmrg    {
266723a0898aSmrg	_fs_pending_reply (conn);
266823a0898aSmrg	return Suspended;
266923a0898aSmrg    }
267041c30155Smrg
267123a0898aSmrg    _fs_client_access (conn, client, FALSE);
267223a0898aSmrg    _fs_client_resolution(conn);
267323a0898aSmrg
267423a0898aSmrg    /* send the request */
267523a0898aSmrg    req.reqType = FS_ListFontsWithXInfo;
26767f7f5e4eSmrg    req.pad = 0;
267723a0898aSmrg    req.maxNames = maxnames;
267823a0898aSmrg    req.nbytes = len;
267923a0898aSmrg    req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
268023a0898aSmrg    _fs_add_req_log(conn, FS_ListFontsWithXInfo);
268123a0898aSmrg    (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
268223a0898aSmrg    (void) _fs_write_pad(conn, pattern, len);
268323a0898aSmrg
268423a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
268541c30155Smrg
268623a0898aSmrg#ifdef NCD
268723a0898aSmrg    if (configData.ExtendedFontDiags) {
268823a0898aSmrg	char        buf[256];
268923a0898aSmrg
269023a0898aSmrg	memcpy(buf, pattern, MIN(256, len));
269123a0898aSmrg	buf[MIN(256, len)] = '\0';
269223a0898aSmrg	printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
269323a0898aSmrg	       buf, fpe->name);
269423a0898aSmrg    }
269523a0898aSmrg#endif
269623a0898aSmrg
269723a0898aSmrg    _fs_prepare_for_reply (conn);
269823a0898aSmrg    return Successful;
269923a0898aSmrg}
270023a0898aSmrg
270123a0898aSmrg/* ARGSUSED */
270223a0898aSmrgstatic int
270341c30155Smrgfs_next_list_with_info(pointer client, FontPathElementPtr fpe,
270441c30155Smrg		       char **namep, int *namelenp,
270523a0898aSmrg		       FontInfoPtr *pFontInfo, int *numFonts,
270623a0898aSmrg		       pointer private)
270723a0898aSmrg{
270823a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
270923a0898aSmrg    FSBlockDataPtr	    blockrec;
271023a0898aSmrg    FSBlockedListInfoPtr    binfo;
271123a0898aSmrg    int			    err;
271223a0898aSmrg
271323a0898aSmrg    /* see if the result is already there */
271423a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
271541c30155Smrg	if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
271623a0898aSmrg	    break;
271723a0898aSmrg
271823a0898aSmrg    if (!blockrec)
271923a0898aSmrg    {
272023a0898aSmrg	/* The only good reason for not finding a blockrec would be if
272123a0898aSmrg	   disconnect/reconnect to the font server wiped it out and the
272223a0898aSmrg	   code that called us didn't do the right thing to create
272323a0898aSmrg	   another one.  Under those circumstances, we need to return an
272423a0898aSmrg	   error to prevent that code from attempting to interpret the
272523a0898aSmrg	   information we don't return.  */
272623a0898aSmrg	return BadFontName;
272723a0898aSmrg    }
272823a0898aSmrg
272923a0898aSmrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
273041c30155Smrg
273123a0898aSmrg    if (binfo->status == FS_LFWI_WAITING)
273223a0898aSmrg	return Suspended;
273323a0898aSmrg
273423a0898aSmrg    *namep = binfo->name;
273523a0898aSmrg    *namelenp = binfo->namelen;
273623a0898aSmrg    *pFontInfo = &binfo->info;
273723a0898aSmrg    *numFonts = binfo->remaining;
273841c30155Smrg
273923a0898aSmrg    /* Restart reply processing from this font server */
274023a0898aSmrg    FD_SET(conn->fs_fd, &_fs_fd_mask);
274123a0898aSmrg    if (fs_reply_ready (conn))
274223a0898aSmrg	_fs_mark_block (conn, FS_COMPLETE_REPLY);
274341c30155Smrg
274423a0898aSmrg    err = blockrec->errcode;
274523a0898aSmrg    switch (binfo->status) {
274623a0898aSmrg    case FS_LFWI_FINISHED:
274723a0898aSmrg	_fs_remove_block_rec(conn, blockrec);
274823a0898aSmrg	break;
274923a0898aSmrg    case FS_LFWI_REPLY:
275023a0898aSmrg	binfo->status = FS_LFWI_WAITING;
275123a0898aSmrg	blockrec->errcode = StillWorking;
275223a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
275323a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
275423a0898aSmrg	break;
275523a0898aSmrg    }
275641c30155Smrg
275723a0898aSmrg    return err;
275823a0898aSmrg}
275923a0898aSmrg
276023a0898aSmrg/*
276123a0898aSmrg * Called when client exits
276223a0898aSmrg */
276323a0898aSmrg
276423a0898aSmrgstatic void
276523a0898aSmrgfs_client_died(pointer client, FontPathElementPtr fpe)
276623a0898aSmrg{
276723a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
276823a0898aSmrg    FSBlockDataPtr  blockrec,
276923a0898aSmrg		    depending;
277023a0898aSmrg    FSClientPtr	    *prev, cur;
277123a0898aSmrg    fsFreeACReq	    freeac;
277223a0898aSmrg
277323a0898aSmrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
277423a0898aSmrg    {
277523a0898aSmrg	if (cur->client == client) {
277623a0898aSmrg	    freeac.reqType = FS_FreeAC;
27777f7f5e4eSmrg	    freeac.pad = 0;
277823a0898aSmrg	    freeac.id = cur->acid;
277923a0898aSmrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
278023a0898aSmrg	    _fs_add_req_log(conn, FS_FreeAC);
278123a0898aSmrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
278223a0898aSmrg	    *prev = cur->next;
27837f7f5e4eSmrg	    free (cur);
278423a0898aSmrg	    break;
278523a0898aSmrg	}
278623a0898aSmrg    }
278723a0898aSmrg    /* find a pending requests */
278823a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
278923a0898aSmrg	if (blockrec->client == client)
279023a0898aSmrg	    break;
279141c30155Smrg
279223a0898aSmrg    if (!blockrec)
279323a0898aSmrg	return;
279441c30155Smrg
279523a0898aSmrg    /* replace the client pointers in this block rec with the chained one */
279641c30155Smrg    if ((depending = blockrec->depending))
279723a0898aSmrg    {
279823a0898aSmrg	blockrec->client = depending->client;
279923a0898aSmrg	blockrec->depending = depending->depending;
280023a0898aSmrg	blockrec = depending;
280123a0898aSmrg    }
280223a0898aSmrg    fs_abort_blockrec(conn, blockrec);
280323a0898aSmrg}
280423a0898aSmrg
280523a0898aSmrgstatic void
280623a0898aSmrg_fs_client_access (FSFpePtr conn, pointer client, Bool sync)
280723a0898aSmrg{
280823a0898aSmrg    FSClientPtr	*prev,	    cur;
280923a0898aSmrg    fsCreateACReq	    crac;
281023a0898aSmrg    fsSetAuthorizationReq   setac;
281123a0898aSmrg    char		    *authorizations;
281223a0898aSmrg    int			    authlen;
281323a0898aSmrg    Bool		    new_cur = FALSE;
28147f7f5e4eSmrg    char		    padding[4] = { 0, 0, 0, 0 };
281523a0898aSmrg
281623a0898aSmrg#ifdef DEBUG
281723a0898aSmrg    if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
281823a0898aSmrg    {
281923a0898aSmrg	fprintf (stderr, "Sending requests without a connection\n");
282023a0898aSmrg    }
282123a0898aSmrg#endif
282223a0898aSmrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
282323a0898aSmrg    {
282423a0898aSmrg	if (cur->client == client)
282523a0898aSmrg	{
282623a0898aSmrg	    if (prev != &conn->clients)
282723a0898aSmrg	    {
282823a0898aSmrg		*prev = cur->next;
282923a0898aSmrg		cur->next = conn->clients;
283023a0898aSmrg		conn->clients = cur;
283123a0898aSmrg	    }
283223a0898aSmrg	    break;
283323a0898aSmrg	}
283423a0898aSmrg    }
283523a0898aSmrg    if (!cur)
283623a0898aSmrg    {
28377f7f5e4eSmrg	cur = malloc (sizeof (FSClientRec));
283823a0898aSmrg	if (!cur)
283923a0898aSmrg	    return;
284023a0898aSmrg	cur->client = client;
284123a0898aSmrg	cur->next = conn->clients;
284223a0898aSmrg	conn->clients = cur;
284323a0898aSmrg	cur->acid = GetNewFontClientID ();
284423a0898aSmrg	new_cur = TRUE;
284523a0898aSmrg    }
284623a0898aSmrg    if (new_cur || cur->auth_generation != client_auth_generation(client))
284723a0898aSmrg    {
284823a0898aSmrg	if (!new_cur)
284923a0898aSmrg	{
285023a0898aSmrg	    fsFreeACReq	freeac;
285123a0898aSmrg	    freeac.reqType = FS_FreeAC;
28527f7f5e4eSmrg	    freeac.pad = 0;
285323a0898aSmrg	    freeac.id = cur->acid;
285423a0898aSmrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
285523a0898aSmrg	    _fs_add_req_log(conn, FS_FreeAC);
285623a0898aSmrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
285723a0898aSmrg	}
285823a0898aSmrg	crac.reqType = FS_CreateAC;
285923a0898aSmrg	crac.num_auths = set_font_authorizations(&authorizations, &authlen,
286023a0898aSmrg						 client);
28617f7f5e4eSmrg	/* Work around bug in xfs versions up through modular release 1.0.8
28627f7f5e4eSmrg	   which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
28637f7f5e4eSmrg	if (crac.num_auths == 0) {
28647f7f5e4eSmrg	    authorizations = padding;
28657f7f5e4eSmrg	    authlen = 4;
28667f7f5e4eSmrg	} else {
28677f7f5e4eSmrg	    authlen = (authlen + 3) & ~0x3;
28687f7f5e4eSmrg	}
286923a0898aSmrg	crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
287023a0898aSmrg	crac.acid = cur->acid;
287123a0898aSmrg	_fs_add_req_log(conn, FS_CreateAC);
287223a0898aSmrg	_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
287323a0898aSmrg	_fs_write(conn, authorizations, authlen);
287423a0898aSmrg	/* ignore reply; we don't even care about it */
287523a0898aSmrg	conn->curacid = 0;
287623a0898aSmrg	cur->auth_generation = client_auth_generation(client);
287723a0898aSmrg    }
287823a0898aSmrg    if (conn->curacid != cur->acid)
287923a0898aSmrg    {
288023a0898aSmrg    	setac.reqType = FS_SetAuthorization;
28817f7f5e4eSmrg	setac.pad = 0;
288223a0898aSmrg    	setac.length = sizeof (fsSetAuthorizationReq) >> 2;
288323a0898aSmrg    	setac.id = cur->acid;
288423a0898aSmrg    	_fs_add_req_log(conn, FS_SetAuthorization);
288523a0898aSmrg    	_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
288623a0898aSmrg	conn->curacid = cur->acid;
288723a0898aSmrg    }
288823a0898aSmrg}
288923a0898aSmrg
289023a0898aSmrg/*
289123a0898aSmrg * Poll a pending connect
289223a0898aSmrg */
289323a0898aSmrg
289423a0898aSmrgstatic int
289523a0898aSmrg_fs_check_connect (FSFpePtr conn)
289623a0898aSmrg{
289723a0898aSmrg    int	    ret;
289841c30155Smrg
289923a0898aSmrg    ret = _fs_poll_connect (conn->trans_conn, 0);
290023a0898aSmrg    switch (ret) {
290123a0898aSmrg    case FSIO_READY:
290223a0898aSmrg	conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
290323a0898aSmrg	FD_SET (conn->fs_fd, &_fs_fd_mask);
290423a0898aSmrg	break;
290523a0898aSmrg    case FSIO_BLOCK:
290623a0898aSmrg	break;
290723a0898aSmrg    }
290823a0898aSmrg    return ret;
290923a0898aSmrg}
291023a0898aSmrg
291123a0898aSmrg/*
291223a0898aSmrg * Return an FSIO status while waiting for the completed connection
291323a0898aSmrg * reply to arrive
291423a0898aSmrg */
291523a0898aSmrg
291623a0898aSmrgstatic fsConnSetup *
291723a0898aSmrg_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
291823a0898aSmrg{
291923a0898aSmrg    int			ret;
292023a0898aSmrg    char		*data;
292123a0898aSmrg    int			headlen;
292223a0898aSmrg    int			len;
292323a0898aSmrg    fsConnSetup		*setup;
292423a0898aSmrg    fsConnSetupAccept	*accept;
292523a0898aSmrg
292623a0898aSmrg    ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
292723a0898aSmrg    if (ret != FSIO_READY)
292823a0898aSmrg    {
292923a0898aSmrg	*error = ret;
293023a0898aSmrg	return 0;
293123a0898aSmrg    }
293241c30155Smrg
293323a0898aSmrg    setup = (fsConnSetup *) data;
293423a0898aSmrg    if (setup->major_version > FS_PROTOCOL)
293523a0898aSmrg    {
293623a0898aSmrg	*error = FSIO_ERROR;
293723a0898aSmrg	return 0;
293823a0898aSmrg    }
293923a0898aSmrg
294023a0898aSmrg    headlen = (SIZEOF (fsConnSetup) +
294123a0898aSmrg	       (setup->alternate_len << 2) +
294223a0898aSmrg	       (setup->auth_len << 2));
294323a0898aSmrg    /* On anything but Success, no extra data is sent */
294423a0898aSmrg    if (setup->status != AuthSuccess)
294523a0898aSmrg    {
294623a0898aSmrg	len = headlen;
294723a0898aSmrg    }
294823a0898aSmrg    else
294923a0898aSmrg    {
295023a0898aSmrg	ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
295123a0898aSmrg	if (ret != FSIO_READY)
295223a0898aSmrg	{
295323a0898aSmrg	    *error = ret;
295423a0898aSmrg	    return 0;
295523a0898aSmrg	}
295623a0898aSmrg	setup = (fsConnSetup *) data;
295723a0898aSmrg	accept = (fsConnSetupAccept *) (data + headlen);
295823a0898aSmrg	len = headlen + (accept->length << 2);
295923a0898aSmrg    }
296023a0898aSmrg    ret = _fs_start_read (conn, len, &data);
296123a0898aSmrg    if (ret != FSIO_READY)
296223a0898aSmrg    {
296323a0898aSmrg	*error = ret;
296423a0898aSmrg	return 0;
296523a0898aSmrg    }
296623a0898aSmrg    *setup_len = len;
296723a0898aSmrg    return (fsConnSetup *) data;
296823a0898aSmrg}
296923a0898aSmrg
297023a0898aSmrgstatic int
297123a0898aSmrg_fs_send_conn_client_prefix (FSFpePtr conn)
297223a0898aSmrg{
297323a0898aSmrg    fsConnClientPrefix	req;
297423a0898aSmrg    int			endian;
297523a0898aSmrg    int			ret;
297623a0898aSmrg
297723a0898aSmrg    /* send setup prefix */
297823a0898aSmrg    endian = 1;
297923a0898aSmrg    if (*(char *) &endian)
298023a0898aSmrg	req.byteOrder = 'l';
298123a0898aSmrg    else
298223a0898aSmrg	req.byteOrder = 'B';
298323a0898aSmrg
298423a0898aSmrg    req.major_version = FS_PROTOCOL;
298523a0898aSmrg    req.minor_version = FS_PROTOCOL_MINOR;
298623a0898aSmrg
298723a0898aSmrg/* XXX add some auth info here */
298823a0898aSmrg    req.num_auths = 0;
298923a0898aSmrg    req.auth_len = 0;
299023a0898aSmrg    ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
299123a0898aSmrg    if (ret != FSIO_READY)
299223a0898aSmrg	return FSIO_ERROR;
299323a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
299423a0898aSmrg    return ret;
299523a0898aSmrg}
299623a0898aSmrg
299723a0898aSmrgstatic int
299823a0898aSmrg_fs_recv_conn_setup (FSFpePtr conn)
299923a0898aSmrg{
300023a0898aSmrg    int			ret = FSIO_ERROR;
300123a0898aSmrg    fsConnSetup		*setup;
300223a0898aSmrg    FSFpeAltPtr		alts;
30039d21a897Sspz    unsigned int	i, alt_len;
300423a0898aSmrg    int			setup_len;
300523a0898aSmrg    char		*alt_save, *alt_names;
300641c30155Smrg
300723a0898aSmrg    setup = _fs_get_conn_setup (conn, &ret, &setup_len);
300823a0898aSmrg    if (!setup)
300923a0898aSmrg	return ret;
301023a0898aSmrg    conn->current_seq = 0;
301123a0898aSmrg    conn->fsMajorVersion = setup->major_version;
301223a0898aSmrg    /*
301323a0898aSmrg     * Create an alternate list from the initial server, but
301423a0898aSmrg     * don't chain looking for alternates.
301523a0898aSmrg     */
301623a0898aSmrg    if (conn->alternate == 0)
301723a0898aSmrg    {
301823a0898aSmrg	/*
301923a0898aSmrg	 * free any existing alternates list, allowing the list to
302023a0898aSmrg	 * be updated
302123a0898aSmrg	 */
302223a0898aSmrg	if (conn->alts)
302323a0898aSmrg	{
30247f7f5e4eSmrg	    free (conn->alts);
302523a0898aSmrg	    conn->alts = 0;
302623a0898aSmrg	    conn->numAlts = 0;
302723a0898aSmrg	}
302823a0898aSmrg	if (setup->num_alternates)
302923a0898aSmrg	{
30309d21a897Sspz	    size_t alt_name_len = setup->alternate_len << 2;
30317f7f5e4eSmrg	    alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
30329d21a897Sspz			   alt_name_len);
303323a0898aSmrg	    if (alts)
303423a0898aSmrg	    {
303523a0898aSmrg		alt_names = (char *) (setup + 1);
303623a0898aSmrg		alt_save = (char *) (alts + setup->num_alternates);
303723a0898aSmrg		for (i = 0; i < setup->num_alternates; i++)
303823a0898aSmrg		{
303923a0898aSmrg		    alts[i].subset = alt_names[0];
304023a0898aSmrg		    alt_len = alt_names[1];
30417673729aSmrg		    if (alt_len >= alt_name_len) {
30427673729aSmrg			/*
30437673729aSmrg			 * Length is longer than setup->alternate_len
30447673729aSmrg			 * told us to allocate room for, assume entire
30457673729aSmrg			 * alternate list is corrupted.
30467673729aSmrg			 */
30479d21a897Sspz#ifdef DEBUG
30487673729aSmrg			fprintf (stderr,
30497673729aSmrg				 "invalid alt list (length %lx >= %lx)\n",
30507673729aSmrg				 (long) alt_len, (long) alt_name_len);
30519d21a897Sspz#endif
30527673729aSmrg			free(alts);
30537673729aSmrg			return FSIO_ERROR;
30547673729aSmrg		    }
305523a0898aSmrg		    alts[i].name = alt_save;
305623a0898aSmrg		    memcpy (alt_save, alt_names + 2, alt_len);
305723a0898aSmrg		    alt_save[alt_len] = '\0';
305823a0898aSmrg		    alt_save += alt_len + 1;
30597673729aSmrg		    alt_name_len -= alt_len + 1;
306023a0898aSmrg		    alt_names += _fs_pad_length (alt_len + 2);
306123a0898aSmrg		}
306223a0898aSmrg		conn->numAlts = setup->num_alternates;
306323a0898aSmrg		conn->alts = alts;
306423a0898aSmrg	    }
306523a0898aSmrg	}
306623a0898aSmrg    }
306723a0898aSmrg    _fs_done_read (conn, setup_len);
306823a0898aSmrg    if (setup->status != AuthSuccess)
306923a0898aSmrg	return FSIO_ERROR;
307023a0898aSmrg    return FSIO_READY;
307123a0898aSmrg}
307223a0898aSmrg
307323a0898aSmrgstatic int
307423a0898aSmrg_fs_open_server (FSFpePtr conn)
307523a0898aSmrg{
307623a0898aSmrg    int	    ret;
307723a0898aSmrg    char    *servername;
307841c30155Smrg
307923a0898aSmrg    if (conn->alternate == 0)
308023a0898aSmrg	servername = conn->servername;
308123a0898aSmrg    else
308223a0898aSmrg	servername = conn->alts[conn->alternate-1].name;
308323a0898aSmrg    conn->trans_conn = _fs_connect (servername, &ret);
308423a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
308523a0898aSmrg    return ret;
308623a0898aSmrg}
308723a0898aSmrg
308823a0898aSmrgstatic char *
308923a0898aSmrg_fs_catalog_name (char *servername)
309023a0898aSmrg{
309123a0898aSmrg    char    *sp;
309223a0898aSmrg
309323a0898aSmrg    sp = strchr (servername, '/');
309423a0898aSmrg    if (!sp)
309523a0898aSmrg	return 0;
309623a0898aSmrg    return strrchr (sp + 1, '/');
309723a0898aSmrg}
309823a0898aSmrg
309923a0898aSmrgstatic int
310023a0898aSmrg_fs_send_init_packets (FSFpePtr conn)
310123a0898aSmrg{
310223a0898aSmrg    fsSetResolutionReq	    srreq;
310323a0898aSmrg    fsSetCataloguesReq	    screq;
310423a0898aSmrg    int			    num_cats,
310523a0898aSmrg			    clen;
310623a0898aSmrg    char		    *catalogues;
310723a0898aSmrg    char		    *cat;
310823a0898aSmrg    char		    len;
310923a0898aSmrg    char		    *end;
311041c30155Smrg    int			    num_res;
311123a0898aSmrg    FontResolutionPtr	    res;
311223a0898aSmrg
311323a0898aSmrg#define	CATALOGUE_SEP	'+'
311423a0898aSmrg
311523a0898aSmrg    res = GetClientResolutions(&num_res);
311641c30155Smrg    if (num_res)
311723a0898aSmrg    {
311823a0898aSmrg	srreq.reqType = FS_SetResolution;
311923a0898aSmrg	srreq.num_resolutions = num_res;
312023a0898aSmrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
312123a0898aSmrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
312223a0898aSmrg
312323a0898aSmrg	_fs_add_req_log(conn, FS_SetResolution);
312423a0898aSmrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
312523a0898aSmrg	    return FSIO_ERROR;
312623a0898aSmrg	if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
312723a0898aSmrg	    return FSIO_ERROR;
312823a0898aSmrg    }
312923a0898aSmrg
313023a0898aSmrg    catalogues = 0;
313123a0898aSmrg    if (conn->alternate != 0)
313223a0898aSmrg	catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
313323a0898aSmrg    if (!catalogues)
313423a0898aSmrg	catalogues = _fs_catalog_name (conn->servername);
313541c30155Smrg
313623a0898aSmrg    if (!catalogues)
313723a0898aSmrg    {
313823a0898aSmrg	conn->has_catalogues = FALSE;
313923a0898aSmrg	return FSIO_READY;
314023a0898aSmrg    }
314123a0898aSmrg    conn->has_catalogues = TRUE;
314241c30155Smrg
314323a0898aSmrg    /* turn cats into counted list */
314423a0898aSmrg    catalogues++;
314523a0898aSmrg
314623a0898aSmrg    cat = catalogues;
314723a0898aSmrg    num_cats = 0;
314823a0898aSmrg    clen = 0;
314923a0898aSmrg    while (*cat)
315023a0898aSmrg    {
315123a0898aSmrg	num_cats++;
315223a0898aSmrg	end = strchr(cat, CATALOGUE_SEP);
315323a0898aSmrg	if (!end)
315423a0898aSmrg	    end = cat + strlen (cat);
315523a0898aSmrg	clen += (end - cat) + 1;	/* length byte + string */
315623a0898aSmrg	cat = end;
315723a0898aSmrg    }
315823a0898aSmrg
315923a0898aSmrg    screq.reqType = FS_SetCatalogues;
316023a0898aSmrg    screq.num_catalogues = num_cats;
316123a0898aSmrg    screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
316241c30155Smrg
316323a0898aSmrg    _fs_add_req_log(conn, FS_SetCatalogues);
316423a0898aSmrg    if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
316523a0898aSmrg	return FSIO_ERROR;
316641c30155Smrg
316723a0898aSmrg    while (*cat)
316823a0898aSmrg    {
316923a0898aSmrg	num_cats++;
317023a0898aSmrg	end = strchr(cat, CATALOGUE_SEP);
317123a0898aSmrg	if (!end)
317223a0898aSmrg	    end = cat + strlen (cat);
317323a0898aSmrg	len = end - cat;
317423a0898aSmrg	if (_fs_write (conn, &len, 1) != FSIO_READY)
317523a0898aSmrg	    return FSIO_ERROR;
317623a0898aSmrg	if (_fs_write (conn, cat, (int) len) != FSIO_READY)
317723a0898aSmrg	    return FSIO_ERROR;
317823a0898aSmrg	cat = end;
317923a0898aSmrg    }
318041c30155Smrg
318123a0898aSmrg    if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
318223a0898aSmrg	return FSIO_ERROR;
318341c30155Smrg
318423a0898aSmrg    return FSIO_READY;
318523a0898aSmrg}
318623a0898aSmrg
318723a0898aSmrgstatic int
318823a0898aSmrg_fs_send_cat_sync (FSFpePtr conn)
318923a0898aSmrg{
319023a0898aSmrg    fsListCataloguesReq	    lcreq;
319141c30155Smrg
319223a0898aSmrg    /*
319323a0898aSmrg     * now sync up with the font server, to see if an error was generated
319423a0898aSmrg     * by a bogus catalogue
319523a0898aSmrg     */
319623a0898aSmrg    lcreq.reqType = FS_ListCatalogues;
31977673729aSmrg    lcreq.data = 0;
319823a0898aSmrg    lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
319923a0898aSmrg    lcreq.maxNames = 0;
320023a0898aSmrg    lcreq.nbytes = 0;
32017f7f5e4eSmrg    lcreq.pad2 = 0;
320223a0898aSmrg    _fs_add_req_log(conn, FS_SetCatalogues);
320323a0898aSmrg    if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
320423a0898aSmrg	return FSIO_ERROR;
320523a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
320623a0898aSmrg    return FSIO_READY;
320723a0898aSmrg}
320823a0898aSmrg
320923a0898aSmrgstatic int
321023a0898aSmrg_fs_recv_cat_sync (FSFpePtr conn)
321123a0898aSmrg{
321223a0898aSmrg    fsGenericReply  *reply;
321323a0898aSmrg    fsError	    *error;
321423a0898aSmrg    int		    err;
321523a0898aSmrg    int		    ret;
321623a0898aSmrg
321723a0898aSmrg    reply = fs_get_reply (conn, &err);
321823a0898aSmrg    if (!reply)
321923a0898aSmrg	return err;
322041c30155Smrg
322123a0898aSmrg    ret = FSIO_READY;
322223a0898aSmrg    if (reply->type == FS_Error)
322323a0898aSmrg    {
322423a0898aSmrg	error = (fsError *) reply;
322523a0898aSmrg	if (error->major_opcode == FS_SetCatalogues)
322623a0898aSmrg	    ret = FSIO_ERROR;
322723a0898aSmrg    }
322823a0898aSmrg    _fs_done_read (conn, reply->length << 2);
322923a0898aSmrg    return ret;
323023a0898aSmrg}
323123a0898aSmrg
323223a0898aSmrgstatic void
323323a0898aSmrg_fs_close_server (FSFpePtr conn)
323423a0898aSmrg{
323523a0898aSmrg    _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
323623a0898aSmrg    if (conn->trans_conn)
323723a0898aSmrg    {
323823a0898aSmrg	_FontTransClose (conn->trans_conn);
323923a0898aSmrg	conn->trans_conn = 0;
324023a0898aSmrg	_fs_io_reinit (conn);
324123a0898aSmrg    }
324223a0898aSmrg    if (conn->fs_fd >= 0)
324323a0898aSmrg    {
324423a0898aSmrg	FD_CLR (conn->fs_fd, &_fs_fd_mask);
324523a0898aSmrg	conn->fs_fd = -1;
324623a0898aSmrg    }
324723a0898aSmrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
324823a0898aSmrg}
324923a0898aSmrg
325023a0898aSmrgstatic int
325123a0898aSmrg_fs_do_setup_connection (FSFpePtr conn)
325223a0898aSmrg{
325323a0898aSmrg    int	    ret;
325441c30155Smrg
325523a0898aSmrg    do
325623a0898aSmrg    {
325723a0898aSmrg#ifdef DEBUG
325823a0898aSmrg	fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
325923a0898aSmrg#endif
326023a0898aSmrg	switch (conn->fs_conn_state) {
326123a0898aSmrg	case FS_CONN_UNCONNECTED:
326223a0898aSmrg	    ret = _fs_open_server (conn);
326323a0898aSmrg	    if (ret == FSIO_BLOCK)
326423a0898aSmrg		conn->fs_conn_state = FS_CONN_CONNECTING;
326523a0898aSmrg	    break;
326623a0898aSmrg	case FS_CONN_CONNECTING:
326723a0898aSmrg	    ret = _fs_check_connect (conn);
326823a0898aSmrg	    break;
326923a0898aSmrg	case FS_CONN_CONNECTED:
327023a0898aSmrg	    ret = _fs_send_conn_client_prefix (conn);
327123a0898aSmrg	    break;
327223a0898aSmrg	case FS_CONN_SENT_PREFIX:
327323a0898aSmrg	    ret = _fs_recv_conn_setup (conn);
327423a0898aSmrg	    break;
327523a0898aSmrg	case FS_CONN_RECV_INIT:
327623a0898aSmrg	    ret = _fs_send_init_packets (conn);
327723a0898aSmrg	    if (conn->has_catalogues)
327823a0898aSmrg		ret = _fs_send_cat_sync (conn);
327923a0898aSmrg	    break;
328023a0898aSmrg	case FS_CONN_SENT_CAT:
328123a0898aSmrg	    if (conn->has_catalogues)
328223a0898aSmrg		ret = _fs_recv_cat_sync (conn);
328323a0898aSmrg	    else
328423a0898aSmrg		ret = FSIO_READY;
328523a0898aSmrg	    break;
328623a0898aSmrg	default:
328723a0898aSmrg	    ret = FSIO_READY;
328823a0898aSmrg	    break;
328923a0898aSmrg	}
329023a0898aSmrg	switch (ret) {
329123a0898aSmrg	case FSIO_READY:
329223a0898aSmrg	    if (conn->fs_conn_state < FS_CONN_RUNNING)
329323a0898aSmrg		conn->fs_conn_state++;
329423a0898aSmrg	    break;
329523a0898aSmrg	case FSIO_BLOCK:
329623a0898aSmrg	    if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
329723a0898aSmrg		break;
329823a0898aSmrg	    ret = FSIO_ERROR;
329923a0898aSmrg	    /* fall through... */
330023a0898aSmrg	case FSIO_ERROR:
330123a0898aSmrg	    _fs_close_server (conn);
330223a0898aSmrg	    /*
330323a0898aSmrg	     * Try the next alternate
330423a0898aSmrg	     */
330523a0898aSmrg	    if (conn->alternate < conn->numAlts)
330623a0898aSmrg	    {
330723a0898aSmrg		conn->alternate++;
330823a0898aSmrg		ret = FSIO_READY;
330923a0898aSmrg	    }
331023a0898aSmrg	    else
331123a0898aSmrg		conn->alternate = 0;
331223a0898aSmrg	    break;
331323a0898aSmrg	}
331423a0898aSmrg    } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
331523a0898aSmrg    if (ret == FSIO_READY)
331623a0898aSmrg	conn->generation = ++generationCount;
331723a0898aSmrg    return ret;
331823a0898aSmrg}
331923a0898aSmrg
332023a0898aSmrgstatic int
332123a0898aSmrg_fs_wait_connect (FSFpePtr conn)
332223a0898aSmrg{
332323a0898aSmrg    int	    ret;
332423a0898aSmrg
332523a0898aSmrg    for (;;)
332623a0898aSmrg    {
332723a0898aSmrg	ret = _fs_do_setup_connection (conn);
332823a0898aSmrg	if (ret != FSIO_BLOCK)
332923a0898aSmrg	    break;
333023a0898aSmrg	if (conn->fs_conn_state <= FS_CONN_CONNECTING)
333123a0898aSmrg	    ret = _fs_poll_connect (conn->trans_conn, 1000);
333223a0898aSmrg	else
333323a0898aSmrg	    ret = _fs_wait_for_readable (conn, 1000);
333423a0898aSmrg	if (ret == FSIO_ERROR)
333523a0898aSmrg	    break;
333623a0898aSmrg    }
333723a0898aSmrg    return ret;
333823a0898aSmrg}
333923a0898aSmrg
334023a0898aSmrg/*
334123a0898aSmrg * Poll a connection in the process of reconnecting
334223a0898aSmrg */
334323a0898aSmrgstatic void
334423a0898aSmrg_fs_check_reconnect (FSFpePtr conn)
334523a0898aSmrg{
334623a0898aSmrg    int	    ret;
334741c30155Smrg
334823a0898aSmrg    ret = _fs_do_setup_connection (conn);
334923a0898aSmrg    switch (ret) {
335023a0898aSmrg    case FSIO_READY:
335123a0898aSmrg	_fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
335223a0898aSmrg	_fs_restart_connection (conn);
335323a0898aSmrg	break;
335423a0898aSmrg    case FSIO_BLOCK:
335523a0898aSmrg	break;
335623a0898aSmrg    case FSIO_ERROR:
335723a0898aSmrg	conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
335823a0898aSmrg	break;
335923a0898aSmrg    }
336023a0898aSmrg}
336123a0898aSmrg
336223a0898aSmrg/*
336323a0898aSmrg * Start the reconnection process
336423a0898aSmrg */
336523a0898aSmrgstatic void
336623a0898aSmrg_fs_start_reconnect (FSFpePtr conn)
336723a0898aSmrg{
336823a0898aSmrg    if (conn->blockState & FS_RECONNECTING)
336923a0898aSmrg	return;
337023a0898aSmrg    conn->alternate = 0;
337123a0898aSmrg    _fs_mark_block (conn, FS_RECONNECTING);
337223a0898aSmrg    _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
337323a0898aSmrg    _fs_check_reconnect (conn);
337423a0898aSmrg}
337523a0898aSmrg
337623a0898aSmrg
337723a0898aSmrgstatic FSFpePtr
337823a0898aSmrg_fs_init_conn (char *servername)
337923a0898aSmrg{
338023a0898aSmrg    FSFpePtr	conn;
338123a0898aSmrg
33827f7f5e4eSmrg    conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
338323a0898aSmrg    if (!conn)
338423a0898aSmrg	return 0;
338523a0898aSmrg    if (!_fs_io_init (conn))
338623a0898aSmrg    {
33877f7f5e4eSmrg	free (conn);
338823a0898aSmrg	return 0;
338923a0898aSmrg    }
339023a0898aSmrg    conn->servername = (char *) (conn + 1);
339123a0898aSmrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
339223a0898aSmrg    conn->fs_fd = -1;
339323a0898aSmrg    strcpy (conn->servername, servername);
339423a0898aSmrg    return conn;
339523a0898aSmrg}
339623a0898aSmrg
339723a0898aSmrgstatic void
339823a0898aSmrg_fs_free_conn (FSFpePtr conn)
339923a0898aSmrg{
340023a0898aSmrg    _fs_close_server (conn);
340123a0898aSmrg    _fs_io_fini (conn);
340223a0898aSmrg    if (conn->alts)
34037f7f5e4eSmrg	free (conn->alts);
34047f7f5e4eSmrg    free (conn);
340523a0898aSmrg}
340623a0898aSmrg
340723a0898aSmrg/*
340823a0898aSmrg * called at server init time
340923a0898aSmrg */
341023a0898aSmrg
341123a0898aSmrgvoid
341223a0898aSmrgfs_register_fpe_functions(void)
341323a0898aSmrg{
341423a0898aSmrg    RegisterFPEFunctions(fs_name_check,
341523a0898aSmrg			 fs_init_fpe,
341623a0898aSmrg			 fs_free_fpe,
341723a0898aSmrg			 fs_reset_fpe,
341823a0898aSmrg			 fs_open_font,
341923a0898aSmrg			 fs_close_font,
342023a0898aSmrg			 fs_list_fonts,
342123a0898aSmrg			 fs_start_list_with_info,
342223a0898aSmrg			 fs_next_list_with_info,
342323a0898aSmrg			 fs_wakeup,
342423a0898aSmrg			 fs_client_died,
342523a0898aSmrg			 _fs_load_glyphs,
342623a0898aSmrg			 NULL,
342723a0898aSmrg			 NULL,
342823a0898aSmrg			 NULL);
342923a0898aSmrg}
3430