fserve.c revision 7f7f5e4e
123a0898aSmrg/* $XdotOrg: lib/Xfont/src/fc/fserve.c,v 1.8 2005/07/09 06:36:12 keithp Exp $ */
223a0898aSmrg/* $Xorg: fserve.c,v 1.4 2001/02/09 02:04:02 xorgcvs Exp $ */
323a0898aSmrg/*
423a0898aSmrg
523a0898aSmrgCopyright 1990, 1998  The Open Group
623a0898aSmrg
723a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
823a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
923a0898aSmrgthe above copyright notice appear in all copies and that both that
1023a0898aSmrgcopyright notice and this permission notice appear in supporting
1123a0898aSmrgdocumentation.
1223a0898aSmrg
1323a0898aSmrgThe above copyright notice and this permission notice shall be included in
1423a0898aSmrgall copies or substantial portions of the Software.
1523a0898aSmrg
1623a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1723a0898aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1823a0898aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1923a0898aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2023a0898aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2123a0898aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2223a0898aSmrg
2323a0898aSmrgExcept as contained in this notice, the name of The Open Group shall not be
2423a0898aSmrgused in advertising or otherwise to promote the sale, use or other dealings
2523a0898aSmrgin this Software without prior written authorization from The Open Group.
2623a0898aSmrg
2723a0898aSmrg*/
2823a0898aSmrg/* $XFree86: xc/lib/font/fc/fserve.c,v 3.26tsi Exp $ */
2923a0898aSmrg
3023a0898aSmrg/*
3123a0898aSmrg * Copyright 1990 Network Computing Devices
3223a0898aSmrg *
3323a0898aSmrg * Permission to use, copy, modify, distribute, and sell this software and
3423a0898aSmrg * its documentation for any purpose is hereby granted without fee, provided
3523a0898aSmrg * that the above copyright notice appear in all copies and that both that
3623a0898aSmrg * copyright notice and this permission notice appear in supporting
3723a0898aSmrg * documentation, and that the names of Network Computing Devices, or Digital
3823a0898aSmrg * not be used in advertising or publicity pertaining to distribution
3923a0898aSmrg * of the software without specific, written prior permission.
4023a0898aSmrg *
4123a0898aSmrg * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
4223a0898aSmrg * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
4323a0898aSmrg * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
4423a0898aSmrg * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
4523a0898aSmrg * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
4623a0898aSmrg * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4723a0898aSmrg * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
4823a0898aSmrg * THIS SOFTWARE.
4923a0898aSmrg *
5023a0898aSmrg * Author:  	Dave Lemke, Network Computing Devices, Inc
5123a0898aSmrg */
5223a0898aSmrg/*
5323a0898aSmrg * font server specific font access
5423a0898aSmrg */
5523a0898aSmrg
5623a0898aSmrg#ifdef HAVE_CONFIG_H
5723a0898aSmrg#include <config.h>
5823a0898aSmrg#endif
5923a0898aSmrg
6023a0898aSmrg#ifdef WIN32
6123a0898aSmrg#define _WILLWINSOCK_
6223a0898aSmrg#endif
6323a0898aSmrg#define FONT_t
6423a0898aSmrg#define TRANS_CLIENT
6523a0898aSmrg#include	"X11/Xtrans/Xtrans.h"
6623a0898aSmrg#include	"X11/Xpoll.h"
6723a0898aSmrg#include	<X11/fonts/FS.h>
6823a0898aSmrg#include	<X11/fonts/FSproto.h>
6923a0898aSmrg#include	<X11/X.h>
7023a0898aSmrg#include	<X11/Xos.h>
7123a0898aSmrg#include	<X11/fonts/fontmisc.h>
7223a0898aSmrg#include	<X11/fonts/fontstruct.h>
7323a0898aSmrg#include	"fservestr.h"
7423a0898aSmrg#include	<X11/fonts/fontutil.h>
7523a0898aSmrg#include	<errno.h>
7623a0898aSmrg
7723a0898aSmrg#include	<time.h>
7823a0898aSmrg#define Time_t time_t
7923a0898aSmrg
8023a0898aSmrg#ifdef NCD
8123a0898aSmrg#include	<ncd/nvram.h>
8223a0898aSmrg#endif
8323a0898aSmrg
8423a0898aSmrg#include <stddef.h>
8523a0898aSmrg
8623a0898aSmrg#ifndef MIN
8723a0898aSmrg#define MIN(a,b)    ((a)<(b)?(a):(b))
8823a0898aSmrg#endif
8923a0898aSmrg#define TimeCmp(a,c,b)	((int) ((a) - (b)) c 0)
9023a0898aSmrg
9123a0898aSmrg#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
9223a0898aSmrg			     (pci)->rightSideBearing || \
9323a0898aSmrg			     (pci)->ascent || \
9423a0898aSmrg			     (pci)->descent || \
9523a0898aSmrg			     (pci)->characterWidth)
9623a0898aSmrg
9723a0898aSmrgextern void ErrorF(const char *f, ...);
9823a0898aSmrg
9923a0898aSmrgstatic int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
10023a0898aSmrgstatic int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
10123a0898aSmrgstatic int fs_read_list_info ( FontPathElementPtr fpe,
10223a0898aSmrg			       FSBlockDataPtr blockrec );
10323a0898aSmrg
10423a0898aSmrgextern fd_set _fs_fd_mask;
10523a0898aSmrg
10623a0898aSmrgstatic void fs_block_handler ( pointer data, OSTimePtr wt,
10723a0898aSmrg			       pointer LastSelectMask );
10823a0898aSmrgstatic int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
10923a0898aSmrg
11023a0898aSmrg/*
11123a0898aSmrg * List of all FPEs
11223a0898aSmrg */
11323a0898aSmrgstatic FSFpePtr fs_fpes;
11423a0898aSmrg/*
11523a0898aSmrg * Union of all FPE blockStates
11623a0898aSmrg */
11723a0898aSmrgstatic CARD32	fs_blockState;
11823a0898aSmrg
11923a0898aSmrgstatic int _fs_restart_connection ( FSFpePtr conn );
12023a0898aSmrgstatic void fs_send_query_bitmaps ( FontPathElementPtr fpe,
12123a0898aSmrg				   FSBlockDataPtr blockrec );
12223a0898aSmrgstatic int fs_send_close_font ( FontPathElementPtr fpe, Font id );
12323a0898aSmrgstatic void fs_client_died ( pointer client, FontPathElementPtr fpe );
12423a0898aSmrgstatic void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
12523a0898aSmrgstatic void _fs_client_resolution ( FSFpePtr conn );
12623a0898aSmrgstatic fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
12723a0898aSmrgstatic int fs_await_reply (FSFpePtr conn);
12823a0898aSmrgstatic void _fs_do_blocked (FSFpePtr conn);
12923a0898aSmrgstatic void fs_cleanup_bfont (FSBlockedFontPtr bfont);
13023a0898aSmrg
13123a0898aSmrgchar _fs_glyph_undefined;
13223a0898aSmrgchar _fs_glyph_requested;
13323a0898aSmrgstatic char _fs_glyph_zero_length;
13423a0898aSmrg
13523a0898aSmrgstatic int  generationCount;
13623a0898aSmrg
13723a0898aSmrgstatic int FontServerRequestTimeout = 30 * 1000;
13823a0898aSmrg
13923a0898aSmrgstatic void
14023a0898aSmrg_fs_close_server (FSFpePtr conn);
14123a0898aSmrg
14223a0898aSmrgstatic FSFpePtr
14323a0898aSmrg_fs_init_conn (char *servername);
14423a0898aSmrg
14523a0898aSmrgstatic int
14623a0898aSmrg_fs_wait_connect (FSFpePtr conn);
14723a0898aSmrg
14823a0898aSmrgstatic int
14923a0898aSmrg_fs_send_init_packets (FSFpePtr conn);
15023a0898aSmrg
15123a0898aSmrgstatic void
15223a0898aSmrg_fs_check_reconnect (FSFpePtr conn);
15323a0898aSmrg
15423a0898aSmrgstatic void
15523a0898aSmrg_fs_start_reconnect (FSFpePtr conn);
15623a0898aSmrg
15723a0898aSmrgstatic void
15823a0898aSmrg_fs_free_conn (FSFpePtr conn);
15923a0898aSmrg
16023a0898aSmrgstatic int
16123a0898aSmrgfs_free_fpe(FontPathElementPtr fpe);
16223a0898aSmrg
16323a0898aSmrg/*
16423a0898aSmrg * Font server access
16523a0898aSmrg *
16623a0898aSmrg * the basic idea for the non-blocking access is to have the function
16723a0898aSmrg * called multiple times until the actual data is returned, instead
16823a0898aSmrg * of ClientBlocked.
16923a0898aSmrg *
17023a0898aSmrg * the first call to the function will cause the request to be sent to
17123a0898aSmrg * the font server, and a block record to be stored in the fpe's list
17223a0898aSmrg * of outstanding requests.  the FS block handler also sticks the
17323a0898aSmrg * proper set of fd's into the select mask.  when data is ready to be
17423a0898aSmrg * read in, the FS wakup handler will be hit.  this will read the
17523a0898aSmrg * data off the wire into the proper block record, and then signal the
17623a0898aSmrg * client that caused the block so that it can restart.  it will then
17723a0898aSmrg * call the access function again, which will realize that the data has
17823a0898aSmrg * arrived and return it.
17923a0898aSmrg */
18023a0898aSmrg
18123a0898aSmrg
18223a0898aSmrg#ifdef DEBUG
18323a0898aSmrgstatic void
18423a0898aSmrg_fs_add_req_log(FSFpePtr conn, int opcode)
18523a0898aSmrg{
18623a0898aSmrg    conn->current_seq++;
18723a0898aSmrg    fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
18823a0898aSmrg	     conn->current_seq, opcode);
18923a0898aSmrg    conn->reqbuffer[conn->reqindex].opcode = opcode;
19023a0898aSmrg    conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
19123a0898aSmrg    conn->reqindex++;
19223a0898aSmrg    if (conn->reqindex == REQUEST_LOG_SIZE)
19323a0898aSmrg	conn->reqindex = 0;
19423a0898aSmrg}
19523a0898aSmrg
19623a0898aSmrgstatic void
19723a0898aSmrg_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
19823a0898aSmrg{
19923a0898aSmrg    int	    i;
20023a0898aSmrg
20123a0898aSmrg    for (i = 0; i < REQUEST_LOG_SIZE; i++)
20223a0898aSmrg	if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
20323a0898aSmrg	    break;
20423a0898aSmrg    if (i == REQUEST_LOG_SIZE)
20523a0898aSmrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: unknown\n",
20623a0898aSmrg		 rep->sequenceNumber);
20723a0898aSmrg    else
20823a0898aSmrg	fprintf (stderr, "\t\t\t\t\tReply:  %5d Opcode: %d\n",
20923a0898aSmrg		 rep->sequenceNumber,
21023a0898aSmrg		 conn->reqbuffer[i].opcode);
21123a0898aSmrg}
21223a0898aSmrg#else
21323a0898aSmrg#define _fs_add_req_log(conn,op)    ((conn)->current_seq++)
21423a0898aSmrg#define _fs_add_rep_log(conn,rep)
21523a0898aSmrg#endif
21623a0898aSmrg
21723a0898aSmrgstatic Bool
21823a0898aSmrgfs_name_check(char *name)
21923a0898aSmrg{
22023a0898aSmrg    /* Just make sure there is a protocol/ prefix */
22123a0898aSmrg    return (name && *name != '/' && strchr(name, '/'));
22223a0898aSmrg}
22323a0898aSmrg
22423a0898aSmrgstatic void
22523a0898aSmrg_fs_client_resolution(FSFpePtr conn)
22623a0898aSmrg{
22723a0898aSmrg    fsSetResolutionReq srreq;
22823a0898aSmrg    int         num_res;
22923a0898aSmrg    FontResolutionPtr res;
23023a0898aSmrg
23123a0898aSmrg    res = GetClientResolutions(&num_res);
23223a0898aSmrg
23323a0898aSmrg    if (num_res) {
23423a0898aSmrg	srreq.reqType = FS_SetResolution;
23523a0898aSmrg	srreq.num_resolutions = num_res;
23623a0898aSmrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
23723a0898aSmrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
23823a0898aSmrg
23923a0898aSmrg	_fs_add_req_log(conn, FS_SetResolution);
24023a0898aSmrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
24123a0898aSmrg	    (void)_fs_write_pad(conn, (char *) res,
24223a0898aSmrg				(num_res * SIZEOF(fsResolution)));
24323a0898aSmrg    }
24423a0898aSmrg}
24523a0898aSmrg
24623a0898aSmrg/*
24723a0898aSmrg * close font server and remove any state associated with
24823a0898aSmrg * this connection - this includes any client records.
24923a0898aSmrg */
25023a0898aSmrg
25123a0898aSmrgstatic void
25223a0898aSmrgfs_close_conn(FSFpePtr conn)
25323a0898aSmrg{
25423a0898aSmrg    FSClientPtr	client, nclient;
25523a0898aSmrg
25623a0898aSmrg    _fs_close_server (conn);
25723a0898aSmrg
25823a0898aSmrg    for (client = conn->clients; client; client = nclient)
25923a0898aSmrg    {
26023a0898aSmrg	nclient = client->next;
2617f7f5e4eSmrg	free (client);
26223a0898aSmrg    }
26323a0898aSmrg    conn->clients = NULL;
26423a0898aSmrg}
26523a0898aSmrg
26623a0898aSmrg/*
26723a0898aSmrg * the wakeup handlers have to be set when the FPE is open, and not
26823a0898aSmrg * removed until it is freed, in order to handle unexpected data, like
26923a0898aSmrg * events
27023a0898aSmrg */
27123a0898aSmrg/* ARGSUSED */
27223a0898aSmrgstatic int
27323a0898aSmrgfs_init_fpe(FontPathElementPtr fpe)
27423a0898aSmrg{
27523a0898aSmrg    FSFpePtr    conn;
27623a0898aSmrg    char       *name;
27723a0898aSmrg    int         err;
27823a0898aSmrg    int		ret;
27923a0898aSmrg
28023a0898aSmrg    /* open font server */
28123a0898aSmrg    /* create FS specific fpe info */
28223a0898aSmrg    name = fpe->name;
28323a0898aSmrg
28423a0898aSmrg    /* hack for old style names */
28523a0898aSmrg    if (*name == ':')
28623a0898aSmrg	name++;			/* skip ':' */
28723a0898aSmrg
28823a0898aSmrg    conn = _fs_init_conn (name);
28923a0898aSmrg    if (!conn)
29023a0898aSmrg	err = AllocError;
29123a0898aSmrg    else
29223a0898aSmrg    {
29323a0898aSmrg	err = init_fs_handlers (fpe, fs_block_handler);
29423a0898aSmrg	if (err != Successful)
29523a0898aSmrg	{
29623a0898aSmrg	    _fs_free_conn (conn);
29723a0898aSmrg	    err = AllocError;
29823a0898aSmrg	}
29923a0898aSmrg	else
30023a0898aSmrg	{
30123a0898aSmrg	    fpe->private = conn;
30223a0898aSmrg	    conn->next = fs_fpes;
30323a0898aSmrg	    fs_fpes = conn;
30423a0898aSmrg	    ret = _fs_wait_connect (conn);
30523a0898aSmrg	    if (ret != FSIO_READY)
30623a0898aSmrg	    {
30723a0898aSmrg		fs_free_fpe (fpe);
30823a0898aSmrg		err = BadFontPath;
30923a0898aSmrg	    }
31023a0898aSmrg	    else
31123a0898aSmrg		err = Successful;
31223a0898aSmrg	}
31323a0898aSmrg    }
31423a0898aSmrg
31523a0898aSmrg    if (err == Successful)
31623a0898aSmrg    {
31723a0898aSmrg#ifdef NCD
31823a0898aSmrg	if (configData.ExtendedFontDiags)
31923a0898aSmrg	    printf("Connected to font server \"%s\"\n", name);
32023a0898aSmrg#endif
32123a0898aSmrg#ifdef DEBUG
32223a0898aSmrg	fprintf (stderr, "connected to FS \"%s\"\n", name);
32323a0898aSmrg#endif
32423a0898aSmrg    }
32523a0898aSmrg    else
32623a0898aSmrg    {
32723a0898aSmrg#ifdef DEBUG
32823a0898aSmrg	fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
32923a0898aSmrg#endif
33023a0898aSmrg#ifdef NCD
33123a0898aSmrg	if (configData.ExtendedFontDiags)
33223a0898aSmrg	    printf("Failed to connect to font server \"%s\"\n", name);
33323a0898aSmrg#endif
33423a0898aSmrg	;
33523a0898aSmrg    }
33623a0898aSmrg    return err;
33723a0898aSmrg}
33823a0898aSmrg
33923a0898aSmrgstatic int
34023a0898aSmrgfs_reset_fpe(FontPathElementPtr fpe)
34123a0898aSmrg{
34223a0898aSmrg    (void) _fs_send_init_packets((FSFpePtr) fpe->private);
34323a0898aSmrg    return Successful;
34423a0898aSmrg}
34523a0898aSmrg
34623a0898aSmrg/*
34723a0898aSmrg * this shouldn't be called till all refs to the FPE are gone
34823a0898aSmrg */
34923a0898aSmrg
35023a0898aSmrgstatic int
35123a0898aSmrgfs_free_fpe(FontPathElementPtr fpe)
35223a0898aSmrg{
35323a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private, *prev;
35423a0898aSmrg
35523a0898aSmrg    /* unhook from chain of all font servers */
35623a0898aSmrg    for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
35723a0898aSmrg    {
35823a0898aSmrg	if (*prev == conn)
35923a0898aSmrg	{
36023a0898aSmrg	    *prev = conn->next;
36123a0898aSmrg	    break;
36223a0898aSmrg	}
36323a0898aSmrg    }
36423a0898aSmrg    _fs_unmark_block (conn, conn->blockState);
36523a0898aSmrg    fs_close_conn(conn);
36623a0898aSmrg    remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
36723a0898aSmrg    _fs_free_conn (conn);
36823a0898aSmrg    fpe->private = (pointer) 0;
36923a0898aSmrg
37023a0898aSmrg#ifdef NCD
37123a0898aSmrg    if (configData.ExtendedFontDiags)
37223a0898aSmrg	printf("Disconnected from font server \"%s\"\n", fpe->name);
37323a0898aSmrg#endif
37423a0898aSmrg#ifdef DEBUG
37523a0898aSmrg    fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
37623a0898aSmrg#endif
37723a0898aSmrg
37823a0898aSmrg    return Successful;
37923a0898aSmrg}
38023a0898aSmrg
38123a0898aSmrgstatic      FSBlockDataPtr
38223a0898aSmrgfs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
38323a0898aSmrg{
38423a0898aSmrg    FSBlockDataPtr blockrec,
38523a0898aSmrg                *prev;
38623a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
38723a0898aSmrg    int         size;
38823a0898aSmrg
38923a0898aSmrg    switch (type) {
39023a0898aSmrg    case FS_OPEN_FONT:
39123a0898aSmrg	size = sizeof(FSBlockedFontRec);
39223a0898aSmrg	break;
39323a0898aSmrg    case FS_LOAD_GLYPHS:
39423a0898aSmrg	size = sizeof(FSBlockedGlyphRec);
39523a0898aSmrg	break;
39623a0898aSmrg    case FS_LIST_FONTS:
39723a0898aSmrg	size = sizeof(FSBlockedListRec);
39823a0898aSmrg	break;
39923a0898aSmrg    case FS_LIST_WITH_INFO:
40023a0898aSmrg	size = sizeof(FSBlockedListInfoRec);
40123a0898aSmrg	break;
40223a0898aSmrg    default:
40323a0898aSmrg	size = 0;
40423a0898aSmrg	break;
40523a0898aSmrg    }
4067f7f5e4eSmrg    blockrec = malloc(sizeof(FSBlockDataRec) + size);
40723a0898aSmrg    if (!blockrec)
40823a0898aSmrg	return (FSBlockDataPtr) 0;
40923a0898aSmrg    blockrec->data = (pointer) (blockrec + 1);
41023a0898aSmrg    blockrec->client = client;
41123a0898aSmrg    blockrec->sequenceNumber = -1;
41223a0898aSmrg    blockrec->errcode = StillWorking;
41323a0898aSmrg    blockrec->type = type;
41423a0898aSmrg    blockrec->depending = 0;
41523a0898aSmrg    blockrec->next = (FSBlockDataPtr) 0;
41623a0898aSmrg
41723a0898aSmrg    /* stick it on the end of the list (since its expected last) */
41823a0898aSmrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
41923a0898aSmrg	;
42023a0898aSmrg    *prev = blockrec;
42123a0898aSmrg
42223a0898aSmrg    return blockrec;
42323a0898aSmrg}
42423a0898aSmrg
42523a0898aSmrgstatic void
42623a0898aSmrg_fs_set_pending_reply (FSFpePtr conn)
42723a0898aSmrg{
42823a0898aSmrg    FSBlockDataPtr  blockrec;
42923a0898aSmrg
43023a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
43123a0898aSmrg	if (blockrec->errcode == StillWorking)
43223a0898aSmrg	    break;
43323a0898aSmrg    if (blockrec)
43423a0898aSmrg    {
43523a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
43623a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
43723a0898aSmrg    }
43823a0898aSmrg    else
43923a0898aSmrg	_fs_unmark_block (conn, FS_PENDING_REPLY);
44023a0898aSmrg}
44123a0898aSmrg
44223a0898aSmrgstatic void
44323a0898aSmrg_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
44423a0898aSmrg{
44523a0898aSmrg    FSBlockDataPtr *prev;
44623a0898aSmrg
44723a0898aSmrg    for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
44823a0898aSmrg	if (*prev == blockrec)
44923a0898aSmrg	{
45023a0898aSmrg	    *prev = blockrec->next;
45123a0898aSmrg	    break;
45223a0898aSmrg	}
45323a0898aSmrg    if (blockrec->type == FS_LOAD_GLYPHS)
45423a0898aSmrg    {
45523a0898aSmrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
45623a0898aSmrg	if (bglyph->num_expected_ranges)
4577f7f5e4eSmrg	    free(bglyph->expected_ranges);
45823a0898aSmrg    }
4597f7f5e4eSmrg    free(blockrec);
46023a0898aSmrg    _fs_set_pending_reply (conn);
46123a0898aSmrg}
46223a0898aSmrg
46323a0898aSmrgstatic void
46423a0898aSmrg_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
46523a0898aSmrg{
46623a0898aSmrg    FSClientsDependingPtr p;
46723a0898aSmrg
46823a0898aSmrg    while ((p = *clients_depending))
46923a0898aSmrg    {
47023a0898aSmrg	*clients_depending = p->next;
47123a0898aSmrg	ClientSignal(p->client);
4727f7f5e4eSmrg	free(p);
47323a0898aSmrg    }
47423a0898aSmrg}
47523a0898aSmrg
47623a0898aSmrgstatic int
47723a0898aSmrg_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
47823a0898aSmrg{
47923a0898aSmrg    FSClientsDependingPtr   new, cd;
48023a0898aSmrg
48123a0898aSmrg    for (; (cd = *clients_depending);
48223a0898aSmrg	 clients_depending = &(*clients_depending)->next)
48323a0898aSmrg    {
48423a0898aSmrg	if (cd->client == client)
48523a0898aSmrg	    return Suspended;
48623a0898aSmrg    }
48723a0898aSmrg
4887f7f5e4eSmrg    new = malloc (sizeof (FSClientsDependingRec));
48923a0898aSmrg    if (!new)
49023a0898aSmrg	return BadAlloc;
49123a0898aSmrg
49223a0898aSmrg    new->client = client;
49323a0898aSmrg    new->next = 0;
49423a0898aSmrg    *clients_depending = new;
49523a0898aSmrg    return Suspended;
49623a0898aSmrg}
49723a0898aSmrg
49823a0898aSmrg/*
49923a0898aSmrg * When a request is aborted due to a font server failure,
50023a0898aSmrg * signal any depending clients to restart their dependant
50123a0898aSmrg * requests
50223a0898aSmrg */
50323a0898aSmrgstatic void
50423a0898aSmrg_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
50523a0898aSmrg{
50623a0898aSmrg    switch(blockrec->type) {
50723a0898aSmrg    case FS_OPEN_FONT: {
50823a0898aSmrg	FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
50923a0898aSmrg
51023a0898aSmrg	fs_cleanup_bfont (bfont);
51123a0898aSmrg	_fs_signal_clients_depending(&bfont->clients_depending);
51223a0898aSmrg	break;
51323a0898aSmrg    }
51423a0898aSmrg    case FS_LOAD_GLYPHS: {
51523a0898aSmrg	FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
51623a0898aSmrg
51723a0898aSmrg	_fs_clean_aborted_loadglyphs(bglyph->pfont,
51823a0898aSmrg				     bglyph->num_expected_ranges,
51923a0898aSmrg				     bglyph->expected_ranges);
52023a0898aSmrg	_fs_signal_clients_depending(&bglyph->clients_depending);
52123a0898aSmrg	break;
52223a0898aSmrg    }
52323a0898aSmrg    case FS_LIST_FONTS:
52423a0898aSmrg	break;
52523a0898aSmrg    case FS_LIST_WITH_INFO: {
52623a0898aSmrg	FSBlockedListInfoPtr binfo;
52723a0898aSmrg	binfo = (FSBlockedListInfoPtr) blockrec->data;
52823a0898aSmrg	if (binfo->status == FS_LFWI_REPLY)
52923a0898aSmrg	    FD_SET(conn->fs_fd, &_fs_fd_mask);
53023a0898aSmrg	_fs_free_props (&binfo->info);
53123a0898aSmrg    }
53223a0898aSmrg    default:
53323a0898aSmrg	break;
53423a0898aSmrg    }
53523a0898aSmrg}
53623a0898aSmrg
53723a0898aSmrgstatic void
53823a0898aSmrgfs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
53923a0898aSmrg{
54023a0898aSmrg    _fs_clean_aborted_blockrec (conn, blockrec);
54123a0898aSmrg    _fs_remove_block_rec (conn, blockrec);
54223a0898aSmrg}
54323a0898aSmrg
54423a0898aSmrg/*
54523a0898aSmrg * Tell the font server we've failed to complete an open and
54623a0898aSmrg * then unload the partially created font
54723a0898aSmrg */
54823a0898aSmrgstatic void
54923a0898aSmrgfs_cleanup_bfont (FSBlockedFontPtr bfont)
55023a0898aSmrg{
55123a0898aSmrg    FSFontDataRec *fsd;
55223a0898aSmrg
55323a0898aSmrg    if (bfont->pfont)
55423a0898aSmrg    {
55523a0898aSmrg	fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
55623a0898aSmrg
55723a0898aSmrg	/* make sure the FS knows we choked on it */
55823a0898aSmrg	fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
55923a0898aSmrg
56023a0898aSmrg	/*
56123a0898aSmrg	 * Either unload the font if it's being opened for
56223a0898aSmrg	 * the first time, or smash the generation field to
56323a0898aSmrg	 * mark this font as an orphan
56423a0898aSmrg	 */
56523a0898aSmrg	if (!(bfont->flags & FontReopen))
56623a0898aSmrg	{
56723a0898aSmrg	    if (bfont->freeFont)
56823a0898aSmrg		(*bfont->pfont->unload_font) (bfont->pfont);
56923a0898aSmrg#ifdef DEBUG
57023a0898aSmrg	    else
57123a0898aSmrg		fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
57223a0898aSmrg#endif
57323a0898aSmrg	    bfont->pfont = 0;
57423a0898aSmrg	}
57523a0898aSmrg	else
57623a0898aSmrg	    fsd->generation = -1;
57723a0898aSmrg    }
57823a0898aSmrg}
57923a0898aSmrg
58023a0898aSmrg/*
58123a0898aSmrg * Check to see if a complete reply is waiting
58223a0898aSmrg */
58323a0898aSmrgstatic fsGenericReply *
58423a0898aSmrgfs_get_reply (FSFpePtr conn, int *error)
58523a0898aSmrg{
58623a0898aSmrg    char	    *buf;
58723a0898aSmrg    fsGenericReply  *rep;
58823a0898aSmrg    int		    ret;
58923a0898aSmrg
59023a0898aSmrg    /* block if the connection is down or paused in lfwi */
59123a0898aSmrg    if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
59223a0898aSmrg    {
59323a0898aSmrg	*error = FSIO_BLOCK;
59423a0898aSmrg	return 0;
59523a0898aSmrg    }
59623a0898aSmrg
59723a0898aSmrg    ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
59823a0898aSmrg    if (ret != FSIO_READY)
59923a0898aSmrg    {
60023a0898aSmrg	*error = FSIO_BLOCK;
60123a0898aSmrg	return 0;
60223a0898aSmrg    }
60323a0898aSmrg
60423a0898aSmrg    rep = (fsGenericReply *) buf;
60523a0898aSmrg
60623a0898aSmrg    ret = _fs_start_read (conn, rep->length << 2, &buf);
60723a0898aSmrg    if (ret != FSIO_READY)
60823a0898aSmrg    {
60923a0898aSmrg	*error = FSIO_BLOCK;
61023a0898aSmrg	return 0;
61123a0898aSmrg    }
61223a0898aSmrg
61323a0898aSmrg    *error = FSIO_READY;
61423a0898aSmrg
61523a0898aSmrg    return (fsGenericReply *) buf;
61623a0898aSmrg}
61723a0898aSmrg
61823a0898aSmrgstatic Bool
61923a0898aSmrgfs_reply_ready (FSFpePtr conn)
62023a0898aSmrg{
62123a0898aSmrg    fsGenericReply  *rep;
62223a0898aSmrg
62323a0898aSmrg    if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
62423a0898aSmrg	return FALSE;
62523a0898aSmrg    if (fs_data_read (conn) < sizeof (fsGenericReply))
62623a0898aSmrg	return FALSE;
62723a0898aSmrg    rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
62823a0898aSmrg    if (fs_data_read (conn) < rep->length << 2)
62923a0898aSmrg	return FALSE;
63023a0898aSmrg    return TRUE;
63123a0898aSmrg}
63223a0898aSmrg
63323a0898aSmrgstatic void
63423a0898aSmrg_fs_pending_reply (FSFpePtr conn)
63523a0898aSmrg{
63623a0898aSmrg    if (!(conn->blockState & FS_PENDING_REPLY))
63723a0898aSmrg    {
63823a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
63923a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
64023a0898aSmrg    }
64123a0898aSmrg}
64223a0898aSmrg
64323a0898aSmrgstatic void
64423a0898aSmrg_fs_prepare_for_reply (FSFpePtr conn)
64523a0898aSmrg{
64623a0898aSmrg    _fs_pending_reply (conn);
64723a0898aSmrg    _fs_flush (conn);
64823a0898aSmrg}
64923a0898aSmrg
65023a0898aSmrg/*
65123a0898aSmrg * Block (for a while) awaiting a complete reply
65223a0898aSmrg */
65323a0898aSmrgstatic int
65423a0898aSmrgfs_await_reply (FSFpePtr conn)
65523a0898aSmrg{
65623a0898aSmrg    int		    ret;
65723a0898aSmrg
65823a0898aSmrg    if (conn->blockState & FS_COMPLETE_REPLY)
65923a0898aSmrg	return FSIO_READY;
66023a0898aSmrg
66123a0898aSmrg    while (!fs_get_reply (conn, &ret))
66223a0898aSmrg    {
66323a0898aSmrg	if (ret != FSIO_BLOCK)
66423a0898aSmrg	    return ret;
66523a0898aSmrg	if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
66623a0898aSmrg	{
66723a0898aSmrg	    _fs_connection_died (conn);
66823a0898aSmrg	    return FSIO_ERROR;
66923a0898aSmrg	}
67023a0898aSmrg    }
67123a0898aSmrg    return FSIO_READY;
67223a0898aSmrg}
67323a0898aSmrg
67423a0898aSmrg/*
67523a0898aSmrg * Process the reply to an OpenBitmapFont request
67623a0898aSmrg */
67723a0898aSmrgstatic int
67823a0898aSmrgfs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
67923a0898aSmrg{
68023a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
68123a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
68223a0898aSmrg    fsOpenBitmapFontReply   *rep;
68323a0898aSmrg    FSBlockDataPtr	    blockOrig;
68423a0898aSmrg    FSBlockedFontPtr	    origBfont;
68523a0898aSmrg    int			    ret;
68623a0898aSmrg
68723a0898aSmrg    rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
68823a0898aSmrg    if (!rep || rep->type == FS_Error)
68923a0898aSmrg    {
69023a0898aSmrg	if (ret == FSIO_BLOCK)
69123a0898aSmrg	    return StillWorking;
69223a0898aSmrg	if (rep)
69323a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
69423a0898aSmrg	fs_cleanup_bfont (bfont);
69523a0898aSmrg	return BadFontName;
69623a0898aSmrg    }
69723a0898aSmrg
69823a0898aSmrg    /* If we're not reopening a font and FS detected a duplicate font
69923a0898aSmrg       open request, replace our reference to the new font with a
70023a0898aSmrg       reference to an existing font (possibly one not finished
70123a0898aSmrg       opening).  If this is a reopen, keep the new font reference...
70223a0898aSmrg       it's got the metrics and extents we read when the font was opened
70323a0898aSmrg       before.  This also gives us the freedom to easily close the font
70423a0898aSmrg       if we we decide (in fs_read_query_info()) that we don't like what
70523a0898aSmrg       we got. */
70623a0898aSmrg
70723a0898aSmrg    if (rep->otherid && !(bfont->flags & FontReopen))
70823a0898aSmrg    {
70923a0898aSmrg	fs_cleanup_bfont (bfont);
71023a0898aSmrg
71123a0898aSmrg	/* Find old font if we're completely done getting it from server. */
71223a0898aSmrg	bfont->pfont = find_old_font(rep->otherid);
71323a0898aSmrg	bfont->freeFont = FALSE;
71423a0898aSmrg	bfont->fontid = rep->otherid;
71523a0898aSmrg	bfont->state = FS_DONE_REPLY;
71623a0898aSmrg	/*
71723a0898aSmrg	 * look for a blocked request to open the same font
71823a0898aSmrg	 */
71923a0898aSmrg	for (blockOrig = conn->blockedRequests;
72023a0898aSmrg		blockOrig;
72123a0898aSmrg		blockOrig = blockOrig->next)
72223a0898aSmrg	{
72323a0898aSmrg	    if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
72423a0898aSmrg	    {
72523a0898aSmrg		origBfont = (FSBlockedFontPtr) blockOrig->data;
72623a0898aSmrg		if (origBfont->fontid == rep->otherid)
72723a0898aSmrg		{
72823a0898aSmrg		    blockrec->depending = blockOrig->depending;
72923a0898aSmrg		    blockOrig->depending = blockrec;
73023a0898aSmrg		    bfont->state = FS_DEPENDING;
73123a0898aSmrg		    bfont->pfont = origBfont->pfont;
73223a0898aSmrg		    break;
73323a0898aSmrg		}
73423a0898aSmrg	    }
73523a0898aSmrg	}
73623a0898aSmrg	if (bfont->pfont == NULL)
73723a0898aSmrg	{
73823a0898aSmrg	    /* XXX - something nasty happened */
73923a0898aSmrg	    ret = BadFontName;
74023a0898aSmrg	}
74123a0898aSmrg	else
74223a0898aSmrg	    ret = AccessDone;
74323a0898aSmrg    }
74423a0898aSmrg    else
74523a0898aSmrg    {
74623a0898aSmrg	bfont->pfont->info.cachable = rep->cachable != 0;
74723a0898aSmrg	bfont->state = FS_INFO_REPLY;
74823a0898aSmrg	/*
74923a0898aSmrg	 * Reset the blockrec for the next reply
75023a0898aSmrg	 */
75123a0898aSmrg	blockrec->sequenceNumber = bfont->queryInfoSequence;
75223a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
75323a0898aSmrg	ret = StillWorking;
75423a0898aSmrg    }
75523a0898aSmrg    _fs_done_read (conn, rep->length << 2);
75623a0898aSmrg    return ret;
75723a0898aSmrg}
75823a0898aSmrg
75923a0898aSmrgstatic Bool
76023a0898aSmrgfs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
76123a0898aSmrg{
76223a0898aSmrg    int	    i;
76323a0898aSmrg
76423a0898aSmrg    if (pInfo1->firstCol != pInfo2->firstCol ||
76523a0898aSmrg	pInfo1->lastCol != pInfo2->lastCol ||
76623a0898aSmrg	pInfo1->firstRow != pInfo2->firstRow ||
76723a0898aSmrg	pInfo1->lastRow != pInfo2->lastRow ||
76823a0898aSmrg	pInfo1->defaultCh != pInfo2->defaultCh ||
76923a0898aSmrg	pInfo1->noOverlap != pInfo2->noOverlap ||
77023a0898aSmrg	pInfo1->terminalFont != pInfo2->terminalFont ||
77123a0898aSmrg	pInfo1->constantMetrics != pInfo2->constantMetrics ||
77223a0898aSmrg	pInfo1->constantWidth != pInfo2->constantWidth ||
77323a0898aSmrg	pInfo1->inkInside != pInfo2->inkInside ||
77423a0898aSmrg	pInfo1->inkMetrics != pInfo2->inkMetrics ||
77523a0898aSmrg	pInfo1->allExist != pInfo2->allExist ||
77623a0898aSmrg	pInfo1->drawDirection != pInfo2->drawDirection ||
77723a0898aSmrg	pInfo1->cachable != pInfo2->cachable ||
77823a0898aSmrg	pInfo1->anamorphic != pInfo2->anamorphic ||
77923a0898aSmrg	pInfo1->maxOverlap != pInfo2->maxOverlap ||
78023a0898aSmrg	pInfo1->fontAscent != pInfo2->fontAscent ||
78123a0898aSmrg	pInfo1->fontDescent != pInfo2->fontDescent ||
78223a0898aSmrg	pInfo1->nprops != pInfo2->nprops)
78323a0898aSmrg	return FALSE;
78423a0898aSmrg
78523a0898aSmrg#define MATCH(xci1, xci2) \
78623a0898aSmrg    (((xci1).leftSideBearing == (xci2).leftSideBearing) && \
78723a0898aSmrg     ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
78823a0898aSmrg     ((xci1).characterWidth == (xci2).characterWidth) && \
78923a0898aSmrg     ((xci1).ascent == (xci2).ascent) && \
79023a0898aSmrg     ((xci1).descent == (xci2).descent) && \
79123a0898aSmrg     ((xci1).attributes == (xci2).attributes))
79223a0898aSmrg
79323a0898aSmrg    if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
79423a0898aSmrg	!MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
79523a0898aSmrg	!MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
79623a0898aSmrg	!MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
79723a0898aSmrg	return FALSE;
79823a0898aSmrg
79923a0898aSmrg#undef MATCH
80023a0898aSmrg
80123a0898aSmrg    for (i = 0; i < pInfo1->nprops; i++)
80223a0898aSmrg	if (pInfo1->isStringProp[i] !=
80323a0898aSmrg		pInfo2->isStringProp[i] ||
80423a0898aSmrg	    pInfo1->props[i].name !=
80523a0898aSmrg		pInfo2->props[i].name ||
80623a0898aSmrg	    pInfo1->props[i].value !=
80723a0898aSmrg		pInfo2->props[i].value)
80823a0898aSmrg	{
80923a0898aSmrg	    return FALSE;
81023a0898aSmrg	}
81123a0898aSmrg    return TRUE;
81223a0898aSmrg}
81323a0898aSmrg
81423a0898aSmrgstatic int
81523a0898aSmrgfs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
81623a0898aSmrg{
81723a0898aSmrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
81823a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
81923a0898aSmrg    fsQueryXInfoReply	*rep;
82023a0898aSmrg    char		*buf;
82123a0898aSmrg    fsPropInfo		*pi;
82223a0898aSmrg    fsPropOffset	*po;
82323a0898aSmrg    pointer		pd;
82423a0898aSmrg    FontInfoPtr		pInfo;
82523a0898aSmrg    FontInfoRec		tempInfo;
82623a0898aSmrg    int			err;
82723a0898aSmrg    int			ret;
82823a0898aSmrg
82923a0898aSmrg    rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
83023a0898aSmrg    if (!rep || rep->type == FS_Error)
83123a0898aSmrg    {
83223a0898aSmrg	if (ret == FSIO_BLOCK)
83323a0898aSmrg	    return StillWorking;
83423a0898aSmrg	if (rep)
83523a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
83623a0898aSmrg	fs_cleanup_bfont (bfont);
83723a0898aSmrg	return BadFontName;
83823a0898aSmrg    }
83923a0898aSmrg
84023a0898aSmrg    /* If this is a reopen, accumulate the query info into a dummy
84123a0898aSmrg       font and compare to our original data. */
84223a0898aSmrg    if (bfont->flags & FontReopen)
84323a0898aSmrg	pInfo = &tempInfo;
84423a0898aSmrg    else
84523a0898aSmrg	pInfo = &bfont->pfont->info;
84623a0898aSmrg
84723a0898aSmrg    buf = (char *) rep;
84823a0898aSmrg    buf += SIZEOF(fsQueryXInfoReply);
84923a0898aSmrg
85023a0898aSmrg    /* move the data over */
85123a0898aSmrg    fsUnpack_XFontInfoHeader(rep, pInfo);
85223a0898aSmrg
85323a0898aSmrg    /* compute accelerators */
85423a0898aSmrg    _fs_init_fontinfo(conn, pInfo);
85523a0898aSmrg
85623a0898aSmrg    /* Compute offsets into the reply */
85723a0898aSmrg    pi = (fsPropInfo *) buf;
85823a0898aSmrg    buf += SIZEOF (fsPropInfo);
85923a0898aSmrg
86023a0898aSmrg    po = (fsPropOffset *) buf;
86123a0898aSmrg    buf += pi->num_offsets * SIZEOF(fsPropOffset);
86223a0898aSmrg
86323a0898aSmrg    pd = (pointer) buf;
86423a0898aSmrg    buf += pi->data_len;
86523a0898aSmrg
86623a0898aSmrg    /* convert the properties and step over the reply */
86723a0898aSmrg    ret = _fs_convert_props(pi, po, pd, pInfo);
86823a0898aSmrg    _fs_done_read (conn, rep->length << 2);
86923a0898aSmrg
87023a0898aSmrg    if (ret == -1)
87123a0898aSmrg    {
87223a0898aSmrg	fs_cleanup_bfont (bfont);
87323a0898aSmrg	return AllocError;
87423a0898aSmrg    }
87523a0898aSmrg
87623a0898aSmrg    if (bfont->flags & FontReopen)
87723a0898aSmrg    {
87823a0898aSmrg	/* We're reopening a font that we lost because of a downed
87923a0898aSmrg	   connection.  In the interest of avoiding corruption from
88023a0898aSmrg	   opening a different font than the old one (we already have
88123a0898aSmrg	   its metrics, extents, and probably some of its glyphs),
88223a0898aSmrg	   verify that the metrics and properties all match.  */
88323a0898aSmrg
88423a0898aSmrg	if (fs_fonts_match (pInfo, &bfont->pfont->info))
88523a0898aSmrg	{
88623a0898aSmrg	    err = Successful;
88723a0898aSmrg	    bfont->state = FS_DONE_REPLY;
88823a0898aSmrg	}
88923a0898aSmrg	else
89023a0898aSmrg	{
89123a0898aSmrg	    fs_cleanup_bfont (bfont);
89223a0898aSmrg	    err = BadFontName;
89323a0898aSmrg	}
89423a0898aSmrg	_fs_free_props (pInfo);
89523a0898aSmrg
89623a0898aSmrg	return err;
89723a0898aSmrg    }
89823a0898aSmrg
89923a0898aSmrg    /*
90023a0898aSmrg     * Ask for terminal format fonts if possible
90123a0898aSmrg     */
90223a0898aSmrg    if (bfont->pfont->info.terminalFont)
90323a0898aSmrg	bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
90423a0898aSmrg			 BitmapFormatImageRectMax);
90523a0898aSmrg
90623a0898aSmrg    /*
90723a0898aSmrg     * Figure out if the whole font should get loaded right now.
90823a0898aSmrg     */
90923a0898aSmrg    if (glyphCachingMode == CACHING_OFF ||
91023a0898aSmrg	(glyphCachingMode == CACHE_16_BIT_GLYPHS
91123a0898aSmrg	 && !bfont->pfont->info.lastRow))
91223a0898aSmrg    {
91323a0898aSmrg	bfont->flags |= FontLoadAll;
91423a0898aSmrg    }
91523a0898aSmrg
91623a0898aSmrg    /*
91723a0898aSmrg     * Ready to send the query bitmaps; the terminal font bit has
91823a0898aSmrg     * been computed and glyphCaching has been considered
91923a0898aSmrg     */
92023a0898aSmrg    if (bfont->flags & FontLoadBitmaps)
92123a0898aSmrg    {
92223a0898aSmrg	fs_send_query_bitmaps (fpe, blockrec);
92323a0898aSmrg	_fs_flush (conn);
92423a0898aSmrg    }
92523a0898aSmrg
92623a0898aSmrg    bfont->state = FS_EXTENT_REPLY;
92723a0898aSmrg
92823a0898aSmrg    /*
92923a0898aSmrg     * Reset the blockrec for the next reply
93023a0898aSmrg     */
93123a0898aSmrg    blockrec->sequenceNumber = bfont->queryExtentsSequence;
93223a0898aSmrg    conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
93323a0898aSmrg
93423a0898aSmrg    return StillWorking;
93523a0898aSmrg}
93623a0898aSmrg
93723a0898aSmrgstatic int
93823a0898aSmrgfs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
93923a0898aSmrg{
94023a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
94123a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
94223a0898aSmrg    FSFontDataPtr	    fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
94323a0898aSmrg    FSFontPtr		    fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
94423a0898aSmrg    fsQueryXExtents16Reply  *rep;
94523a0898aSmrg    char		    *buf;
94623a0898aSmrg    int			    i;
94723a0898aSmrg    int			    numExtents;
94823a0898aSmrg    int			    numInfos;
94923a0898aSmrg    int			    ret;
95023a0898aSmrg    Bool		    haveInk = FALSE; /* need separate ink metrics? */
95123a0898aSmrg    CharInfoPtr		    ci, pCI;
95223a0898aSmrg    char		    *fsci;
95323a0898aSmrg    fsXCharInfo		    fscilocal;
95423a0898aSmrg    FontInfoRec		    *fi = &bfont->pfont->info;
95523a0898aSmrg
95623a0898aSmrg    rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
95723a0898aSmrg    if (!rep || rep->type == FS_Error)
95823a0898aSmrg    {
95923a0898aSmrg	if (ret == FSIO_BLOCK)
96023a0898aSmrg	    return StillWorking;
96123a0898aSmrg	if (rep)
96223a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
96323a0898aSmrg	fs_cleanup_bfont (bfont);
96423a0898aSmrg	return BadFontName;
96523a0898aSmrg    }
96623a0898aSmrg
96723a0898aSmrg    /* move the data over */
96823a0898aSmrg    /* need separate inkMetrics for fixed font server protocol version */
96923a0898aSmrg    numExtents = rep->num_extents;
97023a0898aSmrg    numInfos = numExtents;
97123a0898aSmrg    if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
97223a0898aSmrg    {
97323a0898aSmrg	numInfos *= 2;
97423a0898aSmrg	haveInk = TRUE;
97523a0898aSmrg    }
9767f7f5e4eSmrg    ci = pCI = malloc(sizeof(CharInfoRec) * numInfos);
97723a0898aSmrg
97823a0898aSmrg    if (!pCI)
97923a0898aSmrg    {
98023a0898aSmrg	_fs_done_read (conn, rep->length << 2);
98123a0898aSmrg	fs_cleanup_bfont(bfont);
98223a0898aSmrg	return AllocError;
98323a0898aSmrg    }
98423a0898aSmrg    fsfont->encoding = pCI;
98523a0898aSmrg    if (haveInk)
98623a0898aSmrg	fsfont->inkMetrics = pCI + numExtents;
98723a0898aSmrg    else
98823a0898aSmrg        fsfont->inkMetrics = pCI;
98923a0898aSmrg
99023a0898aSmrg    buf = (char *) rep;
99123a0898aSmrg    buf += SIZEOF (fsQueryXExtents16Reply);
99223a0898aSmrg    fsci = buf;
99323a0898aSmrg
99423a0898aSmrg    fsd->glyphs_to_get = 0;
99523a0898aSmrg    ci = fsfont->inkMetrics;
99623a0898aSmrg    for (i = 0; i < numExtents; i++)
99723a0898aSmrg    {
99823a0898aSmrg	memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
99923a0898aSmrg	_fs_convert_char_info(&fscilocal, &ci->metrics);
100023a0898aSmrg	/* Bounds check. */
100123a0898aSmrg	if (ci->metrics.ascent > fi->maxbounds.ascent)
100223a0898aSmrg	{
100323a0898aSmrg	    ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
100423a0898aSmrg		   fpe->name, fsd->name,
100523a0898aSmrg		   ci->metrics.ascent, fi->maxbounds.ascent);
100623a0898aSmrg	    ci->metrics.ascent = fi->maxbounds.ascent;
100723a0898aSmrg	}
100823a0898aSmrg	if (ci->metrics.descent > fi->maxbounds.descent)
100923a0898aSmrg	{
101023a0898aSmrg	    ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
101123a0898aSmrg		   fpe->name, fsd->name,
101223a0898aSmrg		   ci->metrics.descent, fi->maxbounds.descent);
101323a0898aSmrg	    ci->metrics.descent = fi->maxbounds.descent;
101423a0898aSmrg	}
101523a0898aSmrg	fsci = fsci + SIZEOF(fsXCharInfo);
101623a0898aSmrg	/* Initialize the bits field for later glyph-caching use */
101723a0898aSmrg	if (NONZEROMETRICS(&ci->metrics))
101823a0898aSmrg	{
101923a0898aSmrg	    if (!haveInk &&
102023a0898aSmrg		(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
102123a0898aSmrg		 ci->metrics.ascent == -ci->metrics.descent))
102223a0898aSmrg		pCI[i].bits = &_fs_glyph_zero_length;
102323a0898aSmrg	    else
102423a0898aSmrg	    {
102523a0898aSmrg		pCI[i].bits = &_fs_glyph_undefined;
102623a0898aSmrg		fsd->glyphs_to_get++;
102723a0898aSmrg	    }
102823a0898aSmrg	}
102923a0898aSmrg	else
103023a0898aSmrg	    pCI[i].bits = (char *)0;
103123a0898aSmrg	ci++;
103223a0898aSmrg    }
103323a0898aSmrg
103423a0898aSmrg    /* Done with reply */
103523a0898aSmrg    _fs_done_read (conn, rep->length << 2);
103623a0898aSmrg
103723a0898aSmrg    /* build bitmap metrics, ImageRectMax style */
103823a0898aSmrg    if (haveInk)
103923a0898aSmrg    {
104023a0898aSmrg	CharInfoPtr ii;
104123a0898aSmrg
104223a0898aSmrg	ci = fsfont->encoding;
104323a0898aSmrg	ii = fsfont->inkMetrics;
104423a0898aSmrg	for (i = 0; i < numExtents; i++, ci++, ii++)
104523a0898aSmrg	{
104623a0898aSmrg	    if (NONZEROMETRICS(&ii->metrics))
104723a0898aSmrg	    {
104823a0898aSmrg		ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
104923a0898aSmrg		ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
105023a0898aSmrg		ci->metrics.ascent = FONT_MAX_ASCENT(fi);
105123a0898aSmrg		ci->metrics.descent = FONT_MAX_DESCENT(fi);
105223a0898aSmrg		ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
105323a0898aSmrg		ci->metrics.attributes = ii->metrics.attributes;
105423a0898aSmrg	    }
105523a0898aSmrg	    else
105623a0898aSmrg	    {
105723a0898aSmrg		ci->metrics = ii->metrics;
105823a0898aSmrg	    }
105923a0898aSmrg	    /* Bounds check. */
106023a0898aSmrg	    if (ci->metrics.ascent > fi->maxbounds.ascent)
106123a0898aSmrg	    {
106223a0898aSmrg		ErrorF("fserve: warning: %s %s ascent (%d) "
106323a0898aSmrg		       "> maxascent (%d)\n",
106423a0898aSmrg		       fpe->name, fsd->name,
106523a0898aSmrg		       ci->metrics.ascent, fi->maxbounds.ascent);
106623a0898aSmrg		ci->metrics.ascent = fi->maxbounds.ascent;
106723a0898aSmrg	    }
106823a0898aSmrg	    if (ci->metrics.descent > fi->maxbounds.descent)
106923a0898aSmrg	    {
107023a0898aSmrg		ErrorF("fserve: warning: %s %s descent (%d) "
107123a0898aSmrg		       "> maxdescent (%d)\n",
107223a0898aSmrg		       fpe->name, fsd->name,
107323a0898aSmrg		       ci->metrics.descent, fi->maxbounds.descent);
107423a0898aSmrg		ci->metrics.descent = fi->maxbounds.descent;
107523a0898aSmrg	    }
107623a0898aSmrg	}
107723a0898aSmrg    }
107823a0898aSmrg    {
107923a0898aSmrg	unsigned int r, c, numCols, firstCol;
108023a0898aSmrg
108123a0898aSmrg	firstCol = bfont->pfont->info.firstCol;
108223a0898aSmrg	numCols = bfont->pfont->info.lastCol - firstCol + 1;
108323a0898aSmrg	c = bfont->pfont->info.defaultCh;
108423a0898aSmrg	fsfont->pDefault = 0;
108523a0898aSmrg	if (bfont->pfont->info.lastRow)
108623a0898aSmrg	{
108723a0898aSmrg	    r = c >> 8;
108823a0898aSmrg	    r -= bfont->pfont->info.firstRow;
108923a0898aSmrg	    c &= 0xff;
109023a0898aSmrg	    c -= firstCol;
109123a0898aSmrg	    if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
109223a0898aSmrg		c < numCols)
109323a0898aSmrg		fsfont->pDefault = &pCI[r * numCols + c];
109423a0898aSmrg	}
109523a0898aSmrg	else
109623a0898aSmrg	{
109723a0898aSmrg	    c -= firstCol;
109823a0898aSmrg	    if (c < numCols)
109923a0898aSmrg		fsfont->pDefault = &pCI[c];
110023a0898aSmrg	}
110123a0898aSmrg    }
110223a0898aSmrg    bfont->state = FS_GLYPHS_REPLY;
110323a0898aSmrg
110423a0898aSmrg    if (bfont->flags & FontLoadBitmaps)
110523a0898aSmrg    {
110623a0898aSmrg	/*
110723a0898aSmrg	 * Reset the blockrec for the next reply
110823a0898aSmrg	 */
110923a0898aSmrg	blockrec->sequenceNumber = bfont->queryBitmapsSequence;
111023a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
111123a0898aSmrg	return StillWorking;
111223a0898aSmrg    }
111323a0898aSmrg    return Successful;
111423a0898aSmrg}
111523a0898aSmrg
111623a0898aSmrg#ifdef DEBUG
111723a0898aSmrgstatic char *fs_open_states[] = {
111823a0898aSmrg    "OPEN_REPLY  ",
111923a0898aSmrg    "INFO_REPLY  ",
112023a0898aSmrg    "EXTENT_REPLY",
112123a0898aSmrg    "GLYPHS_REPLY",
112223a0898aSmrg    "DONE_REPLY  ",
112323a0898aSmrg    "DEPENDING   ",
112423a0898aSmrg};
112523a0898aSmrg#endif
112623a0898aSmrg
112723a0898aSmrgstatic int
112823a0898aSmrgfs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
112923a0898aSmrg{
113023a0898aSmrg    FSBlockedFontPtr	bfont = (FSBlockedFontPtr) blockrec->data;
113123a0898aSmrg    int			err;
113223a0898aSmrg
113323a0898aSmrg#ifdef DEBUG
113423a0898aSmrg    fprintf (stderr, "fs_do_open_font state %s %s\n",
113523a0898aSmrg	     fs_open_states[bfont->state],
113623a0898aSmrg	     ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
113723a0898aSmrg#endif
113823a0898aSmrg    err = BadFontName;
113923a0898aSmrg    switch (bfont->state) {
114023a0898aSmrg    case FS_OPEN_REPLY:
114123a0898aSmrg	err = fs_read_open_font(fpe, blockrec);
114223a0898aSmrg	if (err != StillWorking) {	/* already loaded, or error */
114323a0898aSmrg	    /* if font's already loaded, massage error code */
114423a0898aSmrg	    switch (bfont->state) {
114523a0898aSmrg	    case FS_DONE_REPLY:
114623a0898aSmrg		err = Successful;
114723a0898aSmrg		break;
114823a0898aSmrg	    case FS_DEPENDING:
114923a0898aSmrg		err = StillWorking;
115023a0898aSmrg		break;
115123a0898aSmrg	    }
115223a0898aSmrg	}
115323a0898aSmrg	break;
115423a0898aSmrg    case FS_INFO_REPLY:
115523a0898aSmrg	err = fs_read_query_info(fpe, blockrec);
115623a0898aSmrg	break;
115723a0898aSmrg    case FS_EXTENT_REPLY:
115823a0898aSmrg	err = fs_read_extent_info(fpe, blockrec);
115923a0898aSmrg	break;
116023a0898aSmrg    case FS_GLYPHS_REPLY:
116123a0898aSmrg	if (bfont->flags & FontLoadBitmaps)
116223a0898aSmrg	    err = fs_read_glyphs(fpe, blockrec);
116323a0898aSmrg	break;
116423a0898aSmrg    case FS_DEPENDING:		/* can't happen */
116523a0898aSmrg    default:
116623a0898aSmrg	break;
116723a0898aSmrg    }
116823a0898aSmrg#ifdef DEBUG
116923a0898aSmrg    fprintf (stderr, "fs_do_open_font err %d\n", err);
117023a0898aSmrg#endif
117123a0898aSmrg    if (err != StillWorking)
117223a0898aSmrg    {
117323a0898aSmrg	bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
117423a0898aSmrg	while ((blockrec = blockrec->depending))
117523a0898aSmrg	{
117623a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
117723a0898aSmrg	    bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
117823a0898aSmrg	}
117923a0898aSmrg    }
118023a0898aSmrg    return err;
118123a0898aSmrg}
118223a0898aSmrg
118323a0898aSmrgvoid
118423a0898aSmrg_fs_mark_block (FSFpePtr conn, CARD32 mask)
118523a0898aSmrg{
118623a0898aSmrg    conn->blockState |= mask;
118723a0898aSmrg    fs_blockState |= mask;
118823a0898aSmrg}
118923a0898aSmrg
119023a0898aSmrgvoid
119123a0898aSmrg_fs_unmark_block (FSFpePtr conn, CARD32 mask)
119223a0898aSmrg{
119323a0898aSmrg    FSFpePtr	c;
119423a0898aSmrg
119523a0898aSmrg    if (conn->blockState & mask)
119623a0898aSmrg    {
119723a0898aSmrg	conn->blockState &= ~mask;
119823a0898aSmrg	fs_blockState = 0;
119923a0898aSmrg	for (c = fs_fpes; c; c = c->next)
120023a0898aSmrg	    fs_blockState |= c->blockState;
120123a0898aSmrg    }
120223a0898aSmrg}
120323a0898aSmrg
120423a0898aSmrg/* ARGSUSED */
120523a0898aSmrgstatic void
120623a0898aSmrgfs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
120723a0898aSmrg{
120823a0898aSmrg    static struct timeval block_timeout;
120923a0898aSmrg    CARD32	now, earliest, wakeup;
121023a0898aSmrg    int		soonest;
121123a0898aSmrg    FSFpePtr    conn;
121223a0898aSmrg
121323a0898aSmrg    XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
121423a0898aSmrg	      &_fs_fd_mask);
121523a0898aSmrg    /*
121623a0898aSmrg     * Flush all pending output
121723a0898aSmrg     */
121823a0898aSmrg    if (fs_blockState & FS_PENDING_WRITE)
121923a0898aSmrg	for (conn = fs_fpes; conn; conn = conn->next)
122023a0898aSmrg	    if (conn->blockState & FS_PENDING_WRITE)
122123a0898aSmrg		_fs_flush (conn);
122223a0898aSmrg    /*
122323a0898aSmrg     * Check for any fpe with a complete reply, set sleep time to zero
122423a0898aSmrg     */
122523a0898aSmrg    if (fs_blockState & FS_COMPLETE_REPLY)
122623a0898aSmrg    {
122723a0898aSmrg	block_timeout.tv_sec = 0;
122823a0898aSmrg	block_timeout.tv_usec = 0;
122923a0898aSmrg	if (*wt == NULL)
123023a0898aSmrg	    *wt = &block_timeout;
123123a0898aSmrg	else
123223a0898aSmrg	    **wt = block_timeout;
123323a0898aSmrg    }
123423a0898aSmrg    /*
123523a0898aSmrg     * Walk through fpe list computing sleep time
123623a0898aSmrg     */
123723a0898aSmrg    else if (fs_blockState & (FS_BROKEN_WRITE|
123823a0898aSmrg			      FS_BROKEN_CONNECTION|
123923a0898aSmrg			      FS_PENDING_REPLY|
124023a0898aSmrg			      FS_RECONNECTING))
124123a0898aSmrg    {
124223a0898aSmrg	now = GetTimeInMillis ();
124323a0898aSmrg	earliest = now + 10000000;
124423a0898aSmrg	for (conn = fs_fpes; conn; conn = conn->next)
124523a0898aSmrg	{
124623a0898aSmrg	    if (conn->blockState & FS_RECONNECTING)
124723a0898aSmrg	    {
124823a0898aSmrg		wakeup = conn->blockedConnectTime;
124923a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
125023a0898aSmrg		    earliest = wakeup;
125123a0898aSmrg	    }
125223a0898aSmrg	    if (conn->blockState & FS_BROKEN_CONNECTION)
125323a0898aSmrg	    {
125423a0898aSmrg		wakeup = conn->brokenConnectionTime;
125523a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
125623a0898aSmrg		    earliest = wakeup;
125723a0898aSmrg	    }
125823a0898aSmrg	    if (conn->blockState & FS_BROKEN_WRITE)
125923a0898aSmrg	    {
126023a0898aSmrg		wakeup = conn->brokenWriteTime;
126123a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
126223a0898aSmrg		    earliest = wakeup;
126323a0898aSmrg	    }
126423a0898aSmrg	    if (conn->blockState & FS_PENDING_REPLY)
126523a0898aSmrg	    {
126623a0898aSmrg		wakeup = conn->blockedReplyTime;
126723a0898aSmrg		if (TimeCmp (wakeup, <, earliest))
126823a0898aSmrg		    earliest = wakeup;
126923a0898aSmrg	    }
127023a0898aSmrg	}
127123a0898aSmrg	soonest = earliest - now;
127223a0898aSmrg	if (soonest < 0)
127323a0898aSmrg	    soonest = 0;
127423a0898aSmrg	block_timeout.tv_sec = soonest / 1000;
127523a0898aSmrg	block_timeout.tv_usec = (soonest % 1000) * 1000;
127623a0898aSmrg	if (*wt == NULL)
127723a0898aSmrg	    *wt = &block_timeout;
127823a0898aSmrg	else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
127923a0898aSmrg	    **wt = block_timeout;
128023a0898aSmrg    }
128123a0898aSmrg}
128223a0898aSmrg
128323a0898aSmrgstatic void
128423a0898aSmrgfs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
128523a0898aSmrg{
128623a0898aSmrg    if (rep->type == FS_Event && rep->data1 == KeepAlive)
128723a0898aSmrg    {
128823a0898aSmrg	fsNoopReq   req;
128923a0898aSmrg
129023a0898aSmrg	/* ping it back */
129123a0898aSmrg	req.reqType = FS_Noop;
129223a0898aSmrg	req.length = SIZEOF(fsNoopReq) >> 2;
129323a0898aSmrg	_fs_add_req_log(conn, FS_Noop);
129423a0898aSmrg	_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
129523a0898aSmrg    }
129623a0898aSmrg    /* this should suck up unexpected replies and events */
129723a0898aSmrg    _fs_done_read (conn, rep->length << 2);
129823a0898aSmrg}
129923a0898aSmrg
130023a0898aSmrgstatic void
130123a0898aSmrgfs_read_reply (FontPathElementPtr fpe, pointer client)
130223a0898aSmrg{
130323a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
130423a0898aSmrg    FSBlockDataPtr  blockrec;
130523a0898aSmrg    int		    ret;
130623a0898aSmrg    int		    err;
130723a0898aSmrg    fsGenericReply  *rep;
130823a0898aSmrg
130923a0898aSmrg    if ((rep = fs_get_reply (conn, &ret)))
131023a0898aSmrg    {
131123a0898aSmrg	_fs_add_rep_log (conn, rep);
131223a0898aSmrg	for (blockrec = conn->blockedRequests;
131323a0898aSmrg	     blockrec;
131423a0898aSmrg	     blockrec = blockrec->next)
131523a0898aSmrg	{
131623a0898aSmrg	    if (blockrec->sequenceNumber == rep->sequenceNumber)
131723a0898aSmrg		break;
131823a0898aSmrg	}
131923a0898aSmrg	err = Successful;
132023a0898aSmrg	if (!blockrec)
132123a0898aSmrg	{
132223a0898aSmrg	    fs_handle_unexpected(conn, rep);
132323a0898aSmrg	}
132423a0898aSmrg	else
132523a0898aSmrg	{
132623a0898aSmrg	    /*
132723a0898aSmrg	     * go read it, and if we're done,
132823a0898aSmrg	     * wake up the appropriate client
132923a0898aSmrg	     */
133023a0898aSmrg	    switch (blockrec->type) {
133123a0898aSmrg	    case FS_OPEN_FONT:
133223a0898aSmrg		blockrec->errcode = fs_do_open_font(fpe, blockrec);
133323a0898aSmrg		break;
133423a0898aSmrg	    case FS_LOAD_GLYPHS:
133523a0898aSmrg		blockrec->errcode = fs_read_glyphs(fpe, blockrec);
133623a0898aSmrg		break;
133723a0898aSmrg	    case FS_LIST_FONTS:
133823a0898aSmrg		blockrec->errcode = fs_read_list(fpe, blockrec);
133923a0898aSmrg		break;
134023a0898aSmrg	    case FS_LIST_WITH_INFO:
134123a0898aSmrg		blockrec->errcode = fs_read_list_info(fpe, blockrec);
134223a0898aSmrg		break;
134323a0898aSmrg	    default:
134423a0898aSmrg		break;
134523a0898aSmrg	    }
134623a0898aSmrg	    err = blockrec->errcode;
134723a0898aSmrg	    if (err != StillWorking)
134823a0898aSmrg	    {
134923a0898aSmrg		while (blockrec)
135023a0898aSmrg		{
135123a0898aSmrg		    blockrec->errcode = err;
135223a0898aSmrg		    if (client != blockrec->client)
135323a0898aSmrg			ClientSignal(blockrec->client);
135423a0898aSmrg		    blockrec = blockrec->depending;
135523a0898aSmrg		}
135623a0898aSmrg		_fs_unmark_block (conn, FS_PENDING_REPLY);
135723a0898aSmrg	    }
135823a0898aSmrg	}
135923a0898aSmrg	if (fs_reply_ready (conn))
136023a0898aSmrg	    _fs_mark_block (conn, FS_COMPLETE_REPLY);
136123a0898aSmrg	else
136223a0898aSmrg	    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
136323a0898aSmrg    }
136423a0898aSmrg}
136523a0898aSmrg
136623a0898aSmrgstatic int
136723a0898aSmrgfs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
136823a0898aSmrg{
136923a0898aSmrg    fd_set	    *LastSelectMask = (fd_set *) mask;
137023a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
137123a0898aSmrg
137223a0898aSmrg    /*
137323a0898aSmrg     * Don't continue if the fd is -1 (which will be true when the
137423a0898aSmrg     * font server terminates
137523a0898aSmrg     */
137623a0898aSmrg    if ((conn->blockState & FS_RECONNECTING))
137723a0898aSmrg	_fs_check_reconnect (conn);
137823a0898aSmrg    else if ((conn->blockState & FS_COMPLETE_REPLY) ||
137923a0898aSmrg	     (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
138023a0898aSmrg	fs_read_reply (fpe, 0);
138123a0898aSmrg    if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
138223a0898aSmrg	_fs_do_blocked (conn);
138323a0898aSmrg#ifdef DEBUG
138423a0898aSmrg    {
138523a0898aSmrg	FSBlockDataPtr	    blockrec;
138623a0898aSmrg	FSBlockedFontPtr    bfont;
138723a0898aSmrg	FSBlockedListPtr    blist;
138823a0898aSmrg	static CARD32	    lastState;
138923a0898aSmrg	static FSBlockDataPtr	lastBlock;
139023a0898aSmrg
139123a0898aSmrg	if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
139223a0898aSmrg	{
139323a0898aSmrg	    fprintf (stderr, "  Block State 0x%x\n", (int) conn->blockState);
139423a0898aSmrg	    lastState = conn->blockState;
139523a0898aSmrg	    lastBlock = conn->blockedRequests;
139623a0898aSmrg	}
139723a0898aSmrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
139823a0898aSmrg	{
139923a0898aSmrg	    switch (blockrec->type) {
140023a0898aSmrg	    case FS_OPEN_FONT:
140123a0898aSmrg		bfont = (FSBlockedFontPtr) blockrec->data;
140223a0898aSmrg		fprintf (stderr, "  Blocked font errcode %d sequence %d state %s %s\n",
140323a0898aSmrg			 blockrec->errcode,
140423a0898aSmrg			 blockrec->sequenceNumber,
140523a0898aSmrg			 fs_open_states[bfont->state],
140623a0898aSmrg			 bfont->pfont ?
140723a0898aSmrg			 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
140823a0898aSmrg			 "<freed>");
140923a0898aSmrg		break;
141023a0898aSmrg	    case FS_LIST_FONTS:
141123a0898aSmrg		blist = (FSBlockedListPtr) blockrec->data;
141223a0898aSmrg		fprintf (stderr, "  Blocked list errcode %d sequence %d\n",
141323a0898aSmrg			 blockrec->errcode, blockrec->sequenceNumber);
141423a0898aSmrg		break;
141523a0898aSmrg	    default:
141623a0898aSmrg		fprintf (stderr, "  Blocked type %d errcode %d sequence %d\n",
141723a0898aSmrg			 blockrec->type,
141823a0898aSmrg			 blockrec->errcode,
141923a0898aSmrg			 blockrec->sequenceNumber);
142023a0898aSmrg		break;
142123a0898aSmrg	    }
142223a0898aSmrg	}
142323a0898aSmrg    }
142423a0898aSmrg#endif
142523a0898aSmrg    return FALSE;
142623a0898aSmrg}
142723a0898aSmrg
142823a0898aSmrg/*
142923a0898aSmrg * Notice a dead connection and prepare for reconnect
143023a0898aSmrg */
143123a0898aSmrg
143223a0898aSmrgvoid
143323a0898aSmrg_fs_connection_died(FSFpePtr conn)
143423a0898aSmrg{
143523a0898aSmrg    if (conn->blockState & FS_BROKEN_CONNECTION)
143623a0898aSmrg	return;
143723a0898aSmrg    fs_close_conn(conn);
143823a0898aSmrg    conn->brokenConnectionTime = GetTimeInMillis ();
143923a0898aSmrg    _fs_mark_block (conn, FS_BROKEN_CONNECTION);
144023a0898aSmrg    _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
144123a0898aSmrg}
144223a0898aSmrg
144323a0898aSmrg/*
144423a0898aSmrg * Signal clients that the connection has come back up
144523a0898aSmrg */
144623a0898aSmrgstatic int
144723a0898aSmrg_fs_restart_connection(FSFpePtr conn)
144823a0898aSmrg{
144923a0898aSmrg    FSBlockDataPtr block;
145023a0898aSmrg
145123a0898aSmrg    _fs_unmark_block (conn, FS_GIVE_UP);
145223a0898aSmrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
145323a0898aSmrg    {
145423a0898aSmrg	if (block->errcode == StillWorking)
145523a0898aSmrg	{
145623a0898aSmrg	    ClientSignal(block->client);
145723a0898aSmrg	    fs_abort_blockrec(conn, block);
145823a0898aSmrg	}
145923a0898aSmrg    }
146023a0898aSmrg    return TRUE;
146123a0898aSmrg}
146223a0898aSmrg
146323a0898aSmrg/*
146423a0898aSmrg * Declare this font server connection useless
146523a0898aSmrg */
146623a0898aSmrgstatic void
146723a0898aSmrg_fs_giveup (FSFpePtr conn)
146823a0898aSmrg{
146923a0898aSmrg    FSBlockDataPtr  block;
147023a0898aSmrg
147123a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
147223a0898aSmrg	return;
147323a0898aSmrg#ifdef DEBUG
147423a0898aSmrg    fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
147523a0898aSmrg#endif
147623a0898aSmrg    _fs_mark_block (conn, FS_GIVE_UP);
147723a0898aSmrg    while ((block = (FSBlockDataPtr) conn->blockedRequests))
147823a0898aSmrg    {
147923a0898aSmrg	if (block->errcode == StillWorking)
148023a0898aSmrg	{
148123a0898aSmrg	    ClientSignal (block->client);
148223a0898aSmrg	    fs_abort_blockrec (conn, block);
148323a0898aSmrg	}
148423a0898aSmrg    }
148523a0898aSmrg    if (conn->fs_fd >= 0)
148623a0898aSmrg	_fs_connection_died (conn);
148723a0898aSmrg}
148823a0898aSmrg
148923a0898aSmrgstatic void
149023a0898aSmrg_fs_do_blocked (FSFpePtr conn)
149123a0898aSmrg{
149223a0898aSmrg    CARD32      now;
149323a0898aSmrg
149423a0898aSmrg    now = GetTimeInMillis ();
149523a0898aSmrg    if ((conn->blockState & FS_PENDING_REPLY) &&
149623a0898aSmrg	TimeCmp (conn->blockedReplyTime, <=, now))
149723a0898aSmrg    {
149823a0898aSmrg	_fs_giveup (conn);
149923a0898aSmrg    }
150023a0898aSmrg    else
150123a0898aSmrg    {
150223a0898aSmrg	if (conn->blockState & FS_BROKEN_CONNECTION)
150323a0898aSmrg	{
150423a0898aSmrg	    /* Try to reconnect broken connections */
150523a0898aSmrg	    if (TimeCmp (conn->brokenConnectionTime, <=, now))
150623a0898aSmrg		_fs_start_reconnect (conn);
150723a0898aSmrg	}
150823a0898aSmrg	else if (conn->blockState & FS_BROKEN_WRITE)
150923a0898aSmrg	{
151023a0898aSmrg	    /* Try to flush blocked connections */
151123a0898aSmrg	    if (TimeCmp (conn->brokenWriteTime, <=, now))
151223a0898aSmrg		_fs_flush (conn);
151323a0898aSmrg	}
151423a0898aSmrg    }
151523a0898aSmrg}
151623a0898aSmrg
151723a0898aSmrg/*
151823a0898aSmrg * sends the actual request out
151923a0898aSmrg */
152023a0898aSmrg/* ARGSUSED */
152123a0898aSmrgstatic int
152223a0898aSmrgfs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
152323a0898aSmrg		  char *name, int namelen,
152423a0898aSmrg		  fsBitmapFormat format, fsBitmapFormatMask fmask,
152523a0898aSmrg		  XID id, FontPtr *ppfont)
152623a0898aSmrg{
152723a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
152823a0898aSmrg    FontPtr		    font;
152923a0898aSmrg    FSBlockDataPtr	    blockrec = NULL;
153023a0898aSmrg    FSBlockedFontPtr	    bfont;
153123a0898aSmrg    FSFontDataPtr	    fsd;
153223a0898aSmrg    fsOpenBitmapFontReq	    openreq;
153323a0898aSmrg    fsQueryXInfoReq	    inforeq;
153423a0898aSmrg    fsQueryXExtents16Req    extreq;
153523a0898aSmrg    int			    err;
153623a0898aSmrg    unsigned char	    buf[1024];
153723a0898aSmrg
153823a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
153923a0898aSmrg	return BadFontName;
154023a0898aSmrg
154123a0898aSmrg    if (namelen <= 0 || namelen > sizeof (buf) - 1)
154223a0898aSmrg	return BadFontName;
154323a0898aSmrg
154423a0898aSmrg    /*
154523a0898aSmrg     * Get the font structure put together, either by reusing
154623a0898aSmrg     * the existing one or creating a new one
154723a0898aSmrg     */
154823a0898aSmrg    if (flags & FontReopen)
154923a0898aSmrg    {
155023a0898aSmrg	Atom	nameatom, fn = None;
155123a0898aSmrg	int	i;
155223a0898aSmrg
155323a0898aSmrg	font = *ppfont;
155423a0898aSmrg	fsd = (FSFontDataPtr)font->fpePrivate;
155523a0898aSmrg	/* This is an attempt to reopen a font.  Did the font have a
155623a0898aSmrg	   NAME property? */
155723a0898aSmrg	if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
155823a0898aSmrg	{
155923a0898aSmrg	    for (i = 0; i < font->info.nprops; i++)
156023a0898aSmrg		if (font->info.props[i].name == nameatom &&
156123a0898aSmrg		    font->info.isStringProp[i])
156223a0898aSmrg		{
156323a0898aSmrg		    fn = font->info.props[i].value;
156423a0898aSmrg		    break;
156523a0898aSmrg		}
156623a0898aSmrg	}
156723a0898aSmrg	if (fn == None || !(name = NameForAtom(fn)))
156823a0898aSmrg	{
156923a0898aSmrg	    name = fsd->name;
157023a0898aSmrg	    namelen = fsd->namelen;
157123a0898aSmrg	}
157223a0898aSmrg	else
157323a0898aSmrg	    namelen = strlen(name);
157423a0898aSmrg    }
157523a0898aSmrg    else
157623a0898aSmrg    {
157723a0898aSmrg	font = fs_create_font (fpe, name, namelen, format, fmask);
157823a0898aSmrg	if (!font)
157923a0898aSmrg	    return AllocError;
158023a0898aSmrg
158123a0898aSmrg	fsd = (FSFontDataPtr)font->fpePrivate;
158223a0898aSmrg    }
158323a0898aSmrg
158423a0898aSmrg    /* make a new block record, and add it to the end of the list */
158523a0898aSmrg    blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
158623a0898aSmrg    if (!blockrec)
158723a0898aSmrg    {
158823a0898aSmrg	if (!(flags & FontReopen))
158923a0898aSmrg	    (*font->unload_font) (font);
159023a0898aSmrg	return AllocError;
159123a0898aSmrg    }
159223a0898aSmrg
159323a0898aSmrg    /*
159423a0898aSmrg     * Must check this before generating any protocol, otherwise we'll
159523a0898aSmrg     * mess up a reconnect in progress
159623a0898aSmrg     */
159723a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
159823a0898aSmrg    {
159923a0898aSmrg	_fs_pending_reply (conn);
160023a0898aSmrg	return Suspended;
160123a0898aSmrg    }
160223a0898aSmrg
160323a0898aSmrg    fsd->generation = conn->generation;
160423a0898aSmrg
160523a0898aSmrg    bfont = (FSBlockedFontPtr) blockrec->data;
160623a0898aSmrg    bfont->fontid = fsd->fontid;
160723a0898aSmrg    bfont->pfont = font;
160823a0898aSmrg    bfont->state = FS_OPEN_REPLY;
160923a0898aSmrg    bfont->flags = flags;
161023a0898aSmrg    bfont->format = fsd->format;
161123a0898aSmrg    bfont->clients_depending = (FSClientsDependingPtr)0;
161223a0898aSmrg    bfont->freeFont = (flags & FontReopen) == 0;
161323a0898aSmrg
161423a0898aSmrg    _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
161523a0898aSmrg    _fs_client_resolution(conn);
161623a0898aSmrg
161723a0898aSmrg    /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
161823a0898aSmrg    buf[0] = (unsigned char) namelen;
161923a0898aSmrg    memcpy(&buf[1], name, namelen);
162023a0898aSmrg    openreq.reqType = FS_OpenBitmapFont;
16217f7f5e4eSmrg    openreq.pad = 0;
162223a0898aSmrg    openreq.fid = fsd->fontid;
162323a0898aSmrg    openreq.format_hint = fsd->format;
162423a0898aSmrg    openreq.format_mask = fsd->fmask;
162523a0898aSmrg    openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
162623a0898aSmrg
162723a0898aSmrg    _fs_add_req_log(conn, FS_OpenBitmapFont);
162823a0898aSmrg    _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
162923a0898aSmrg    _fs_write_pad(conn, (char *) buf, namelen + 1);
163023a0898aSmrg
163123a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
163223a0898aSmrg
163323a0898aSmrg    inforeq.reqType = FS_QueryXInfo;
16347f7f5e4eSmrg    inforeq.pad = 0;
163523a0898aSmrg    inforeq.id = fsd->fontid;
163623a0898aSmrg    inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
163723a0898aSmrg
163823a0898aSmrg    bfont->queryInfoSequence = conn->current_seq + 1;
163923a0898aSmrg
164023a0898aSmrg    _fs_add_req_log(conn, FS_QueryXInfo);
164123a0898aSmrg    _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
164223a0898aSmrg
164323a0898aSmrg    if (!(bfont->flags & FontReopen))
164423a0898aSmrg    {
164523a0898aSmrg	extreq.reqType = FS_QueryXExtents16;
164623a0898aSmrg	extreq.range = fsTrue;
164723a0898aSmrg	extreq.fid = fsd->fontid;
164823a0898aSmrg	extreq.num_ranges = 0;
164923a0898aSmrg	extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
165023a0898aSmrg
165123a0898aSmrg	bfont->queryExtentsSequence = conn->current_seq + 1;
165223a0898aSmrg
165323a0898aSmrg	_fs_add_req_log(conn, FS_QueryXExtents16);
165423a0898aSmrg	_fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
165523a0898aSmrg    }
165623a0898aSmrg
165723a0898aSmrg#ifdef NCD
165823a0898aSmrg    if (configData.ExtendedFontDiags)
165923a0898aSmrg    {
166023a0898aSmrg	memcpy(buf, name, MIN(256, namelen));
166123a0898aSmrg	buf[MIN(256, namelen)] = '\0';
166223a0898aSmrg	printf("Requesting font \"%s\" from font server \"%s\"\n",
166323a0898aSmrg	       buf, font->fpe->name);
166423a0898aSmrg    }
166523a0898aSmrg#endif
166623a0898aSmrg    _fs_prepare_for_reply (conn);
166723a0898aSmrg
166823a0898aSmrg    err = blockrec->errcode;
166923a0898aSmrg    if (bfont->flags & FontOpenSync)
167023a0898aSmrg    {
167123a0898aSmrg	while (blockrec->errcode == StillWorking)
167223a0898aSmrg	{
167323a0898aSmrg	    if (fs_await_reply (conn) != FSIO_READY)
167423a0898aSmrg	    {
167523a0898aSmrg		blockrec->errcode = BadFontName;
167623a0898aSmrg		break;
167723a0898aSmrg	    }
167823a0898aSmrg	    fs_read_reply (font->fpe, client);
167923a0898aSmrg	}
168023a0898aSmrg	err = blockrec->errcode;
168123a0898aSmrg	if (err == Successful)
168223a0898aSmrg	    *ppfont = bfont->pfont;
168323a0898aSmrg	else
168423a0898aSmrg	    fs_cleanup_bfont (bfont);
168523a0898aSmrg	bfont->freeFont = FALSE;
168623a0898aSmrg	_fs_remove_block_rec (conn, blockrec);
168723a0898aSmrg    }
168823a0898aSmrg    return err == StillWorking ? Suspended : err;
168923a0898aSmrg}
169023a0898aSmrg
169123a0898aSmrgstatic void
169223a0898aSmrgfs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
169323a0898aSmrg{
169423a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
169523a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
169623a0898aSmrg    fsQueryXBitmaps16Req    bitreq;
169723a0898aSmrg
169823a0898aSmrg    /* send the request */
169923a0898aSmrg    bitreq.reqType = FS_QueryXBitmaps16;
170023a0898aSmrg    bitreq.fid = bfont->fontid;
170123a0898aSmrg    bitreq.format = bfont->format;
170223a0898aSmrg    bitreq.range = TRUE;
170323a0898aSmrg    bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
170423a0898aSmrg    bitreq.num_ranges = 0;
170523a0898aSmrg
170623a0898aSmrg    bfont->queryBitmapsSequence = conn->current_seq + 1;
170723a0898aSmrg
170823a0898aSmrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
170923a0898aSmrg    _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
171023a0898aSmrg}
171123a0898aSmrg
171223a0898aSmrg/* ARGSUSED */
171323a0898aSmrgstatic int
171423a0898aSmrgfs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
171523a0898aSmrg	     char *name, int namelen,
171623a0898aSmrg	     fsBitmapFormat format, fsBitmapFormatMask fmask,
171723a0898aSmrg	     XID id, FontPtr *ppfont,
171823a0898aSmrg	     char **alias, FontPtr non_cachable_font)
171923a0898aSmrg{
172023a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
172123a0898aSmrg    FSBlockDataPtr	blockrec;
172223a0898aSmrg    FSBlockedFontPtr	bfont;
172323a0898aSmrg    int			err;
172423a0898aSmrg
172523a0898aSmrg    /* libfont interface expects ImageRectMin glyphs */
172623a0898aSmrg    format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
172723a0898aSmrg
172823a0898aSmrg    *alias = (char *) 0;
172923a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
173023a0898aSmrg    {
173123a0898aSmrg	if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
173223a0898aSmrg	{
173323a0898aSmrg	    err = blockrec->errcode;
173423a0898aSmrg	    if (err == StillWorking)
173523a0898aSmrg		return Suspended;
173623a0898aSmrg
173723a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
173823a0898aSmrg	    if (err == Successful)
173923a0898aSmrg		*ppfont = bfont->pfont;
174023a0898aSmrg	    else
174123a0898aSmrg		fs_cleanup_bfont (bfont);
174223a0898aSmrg	    _fs_remove_block_rec (conn, blockrec);
174323a0898aSmrg	    return err;
174423a0898aSmrg	}
174523a0898aSmrg    }
174623a0898aSmrg    return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
174723a0898aSmrg			     id, ppfont);
174823a0898aSmrg}
174923a0898aSmrg
175023a0898aSmrg/* ARGSUSED */
175123a0898aSmrgstatic int
175223a0898aSmrgfs_send_close_font(FontPathElementPtr fpe, Font id)
175323a0898aSmrg{
175423a0898aSmrg    FSFpePtr    conn = (FSFpePtr) fpe->private;
175523a0898aSmrg    fsCloseReq  req;
175623a0898aSmrg
175723a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
175823a0898aSmrg	return Successful;
175923a0898aSmrg    /* tell the font server to close the font */
176023a0898aSmrg    req.reqType = FS_CloseFont;
17617f7f5e4eSmrg    req.pad = 0;
176223a0898aSmrg    req.length = SIZEOF(fsCloseReq) >> 2;
176323a0898aSmrg    req.id = id;
176423a0898aSmrg    _fs_add_req_log(conn, FS_CloseFont);
176523a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
176623a0898aSmrg
176723a0898aSmrg    return Successful;
176823a0898aSmrg}
176923a0898aSmrg
177023a0898aSmrg/* ARGSUSED */
177123a0898aSmrgstatic void
177223a0898aSmrgfs_close_font(FontPathElementPtr fpe, FontPtr pfont)
177323a0898aSmrg{
177423a0898aSmrg    FSFontDataPtr   fsd = (FSFontDataPtr) pfont->fpePrivate;
177523a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
177623a0898aSmrg
177723a0898aSmrg    if (conn->generation == fsd->generation)
177823a0898aSmrg	fs_send_close_font(fpe, fsd->fontid);
177923a0898aSmrg
178023a0898aSmrg#ifdef DEBUG
178123a0898aSmrg    {
178223a0898aSmrg	FSBlockDataPtr	    blockrec;
178323a0898aSmrg	FSBlockedFontPtr    bfont;
178423a0898aSmrg
178523a0898aSmrg	for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
178623a0898aSmrg	{
178723a0898aSmrg	    if (blockrec->type == FS_OPEN_FONT)
178823a0898aSmrg	    {
178923a0898aSmrg		bfont = (FSBlockedFontPtr) blockrec->data;
179023a0898aSmrg		if (bfont->pfont == pfont)
179123a0898aSmrg		    fprintf (stderr, "closing font which hasn't been opened\n");
179223a0898aSmrg	    }
179323a0898aSmrg	}
179423a0898aSmrg    }
179523a0898aSmrg#endif
179623a0898aSmrg    (*pfont->unload_font) (pfont);
179723a0898aSmrg}
179823a0898aSmrg
179923a0898aSmrgstatic int
180023a0898aSmrgfs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
180123a0898aSmrg{
180223a0898aSmrg    FSBlockedGlyphPtr	    bglyph = (FSBlockedGlyphPtr) blockrec->data;
180323a0898aSmrg    FSBlockedFontPtr	    bfont = (FSBlockedFontPtr) blockrec->data;
180423a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
180523a0898aSmrg    FontPtr		    pfont = bglyph->pfont;
180623a0898aSmrg					/* works for either blocked font
180723a0898aSmrg					   or glyph rec...  pfont is at
180823a0898aSmrg					   the very beginning of both
180923a0898aSmrg					   blockrec->data structures */
181023a0898aSmrg    FSFontDataPtr	    fsd = (FSFontDataPtr) (pfont->fpePrivate);
181123a0898aSmrg    FSFontPtr		    fsdata = (FSFontPtr) pfont->fontPrivate;
181223a0898aSmrg    FontInfoPtr		    pfi = &pfont->info;
181323a0898aSmrg    fsQueryXBitmaps16Reply  *rep;
181423a0898aSmrg    char		    *buf;
181523a0898aSmrg    fsOffset32		    *ppbits;
181623a0898aSmrg    fsOffset32		    local_off;
181723a0898aSmrg    char		    *off_adr;
181823a0898aSmrg    pointer		    pbitmaps;
181923a0898aSmrg    char		    *bits, *allbits;
182023a0898aSmrg#ifdef DEBUG
182123a0898aSmrg    char		    *origallbits;
182223a0898aSmrg#endif
182323a0898aSmrg    int			    i,
182423a0898aSmrg			    err;
182523a0898aSmrg    int			    nranges = 0;
182623a0898aSmrg    int			    ret;
182723a0898aSmrg    fsRange		    *nextrange = 0;
182823a0898aSmrg    unsigned long	    minchar, maxchar;
182923a0898aSmrg
183023a0898aSmrg    rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
183123a0898aSmrg    if (!rep || rep->type == FS_Error)
183223a0898aSmrg    {
183323a0898aSmrg	if (ret == FSIO_BLOCK)
183423a0898aSmrg	    return StillWorking;
183523a0898aSmrg	if (rep)
183623a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
183723a0898aSmrg	err = AllocError;
183823a0898aSmrg	goto bail;
183923a0898aSmrg    }
184023a0898aSmrg
184123a0898aSmrg    buf = (char *) rep;
184223a0898aSmrg    buf += SIZEOF (fsQueryXBitmaps16Reply);
184323a0898aSmrg
184423a0898aSmrg    ppbits = (fsOffset32 *) buf;
184523a0898aSmrg    buf += SIZEOF (fsOffset32) * (rep->num_chars);
184623a0898aSmrg
184723a0898aSmrg    pbitmaps = (pointer ) buf;
184823a0898aSmrg
184923a0898aSmrg    if (blockrec->type == FS_LOAD_GLYPHS)
185023a0898aSmrg    {
185123a0898aSmrg	nranges = bglyph->num_expected_ranges;
185223a0898aSmrg	nextrange = bglyph->expected_ranges;
185323a0898aSmrg    }
185423a0898aSmrg
185523a0898aSmrg    /* place the incoming glyphs */
185623a0898aSmrg    if (nranges)
185723a0898aSmrg    {
185823a0898aSmrg	/* We're operating under the assumption that the ranges
185923a0898aSmrg	   requested in the LoadGlyphs call were all legal for this
186023a0898aSmrg	   font, and that individual ranges do not cover multiple
186123a0898aSmrg	   rows...  fs_build_range() is designed to ensure this. */
186223a0898aSmrg	minchar = (nextrange->min_char_high - pfi->firstRow) *
186323a0898aSmrg		  (pfi->lastCol - pfi->firstCol + 1) +
186423a0898aSmrg		  nextrange->min_char_low - pfi->firstCol;
186523a0898aSmrg	maxchar = (nextrange->max_char_high - pfi->firstRow) *
186623a0898aSmrg		  (pfi->lastCol - pfi->firstCol + 1) +
186723a0898aSmrg		  nextrange->max_char_low - pfi->firstCol;
186823a0898aSmrg	nextrange++;
186923a0898aSmrg    }
187023a0898aSmrg    else
187123a0898aSmrg    {
187223a0898aSmrg	minchar = 0;
187323a0898aSmrg	maxchar = rep->num_chars;
187423a0898aSmrg    }
187523a0898aSmrg
187623a0898aSmrg    off_adr = (char *)ppbits;
187723a0898aSmrg
187823a0898aSmrg    allbits = fs_alloc_glyphs (pfont, rep->nbytes);
187923a0898aSmrg
188023a0898aSmrg    if (!allbits)
188123a0898aSmrg    {
188223a0898aSmrg	err = AllocError;
188323a0898aSmrg	goto bail;
188423a0898aSmrg    }
188523a0898aSmrg
188623a0898aSmrg#ifdef DEBUG
188723a0898aSmrg    origallbits = allbits;
188823a0898aSmrg    fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
188923a0898aSmrg	     (int) rep->num_chars, (int) rep->nbytes, fsd->name);
189023a0898aSmrg#endif
189123a0898aSmrg
189223a0898aSmrg    for (i = 0; i < rep->num_chars; i++)
189323a0898aSmrg    {
189423a0898aSmrg	memcpy(&local_off, off_adr, SIZEOF(fsOffset32));	/* align it */
189523a0898aSmrg	if (blockrec->type == FS_OPEN_FONT ||
189623a0898aSmrg	    fsdata->encoding[minchar].bits == &_fs_glyph_requested)
189723a0898aSmrg	{
189823a0898aSmrg	    /*
189923a0898aSmrg	     * Broken X font server returns bits for missing characters
190023a0898aSmrg	     * when font is padded
190123a0898aSmrg	     */
190223a0898aSmrg	    if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
190323a0898aSmrg	    {
190423a0898aSmrg		if (local_off.length)
190523a0898aSmrg		{
190623a0898aSmrg		    bits = allbits;
190723a0898aSmrg		    allbits += local_off.length;
190823a0898aSmrg		    memcpy(bits, (char *)pbitmaps + local_off.position,
190923a0898aSmrg			   local_off.length);
191023a0898aSmrg		}
191123a0898aSmrg		else
191223a0898aSmrg		    bits = &_fs_glyph_zero_length;
191323a0898aSmrg	    }
191423a0898aSmrg	    else
191523a0898aSmrg		bits = 0;
191623a0898aSmrg	    if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
191723a0898aSmrg		fsd->glyphs_to_get--;
191823a0898aSmrg	    fsdata->encoding[minchar].bits = bits;
191923a0898aSmrg	}
192023a0898aSmrg	if (minchar++ == maxchar)
192123a0898aSmrg	{
192223a0898aSmrg	    if (!--nranges) break;
192323a0898aSmrg	    minchar = (nextrange->min_char_high - pfi->firstRow) *
192423a0898aSmrg		      (pfi->lastCol - pfi->firstCol + 1) +
192523a0898aSmrg		      nextrange->min_char_low - pfi->firstCol;
192623a0898aSmrg	    maxchar = (nextrange->max_char_high - pfi->firstRow) *
192723a0898aSmrg		      (pfi->lastCol - pfi->firstCol + 1) +
192823a0898aSmrg		      nextrange->max_char_low - pfi->firstCol;
192923a0898aSmrg	    nextrange++;
193023a0898aSmrg	}
193123a0898aSmrg	off_adr += SIZEOF(fsOffset32);
193223a0898aSmrg    }
193323a0898aSmrg#ifdef DEBUG
193423a0898aSmrg    fprintf (stderr, "Used %d bytes instead of %d\n",
193523a0898aSmrg	     (int) (allbits - origallbits), (int) rep->nbytes);
193623a0898aSmrg#endif
193723a0898aSmrg
193823a0898aSmrg    if (blockrec->type == FS_OPEN_FONT)
193923a0898aSmrg    {
194023a0898aSmrg	fsd->glyphs_to_get = 0;
194123a0898aSmrg	bfont->state = FS_DONE_REPLY;
194223a0898aSmrg    }
194323a0898aSmrg    err = Successful;
194423a0898aSmrg
194523a0898aSmrgbail:
194623a0898aSmrg    _fs_done_read (conn, rep->length << 2);
194723a0898aSmrg    return err;
194823a0898aSmrg}
194923a0898aSmrg
195023a0898aSmrgstatic int
195123a0898aSmrgfs_send_load_glyphs(pointer client, FontPtr pfont,
195223a0898aSmrg		    int nranges, fsRange *ranges)
195323a0898aSmrg{
195423a0898aSmrg    FontPathElementPtr	    fpe = pfont->fpe;
195523a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
195623a0898aSmrg    FSBlockedGlyphPtr	    blockedglyph;
195723a0898aSmrg    fsQueryXBitmaps16Req    req;
195823a0898aSmrg    FSBlockDataPtr	    blockrec;
195923a0898aSmrg
196023a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
196123a0898aSmrg	return BadCharRange;
196223a0898aSmrg
196323a0898aSmrg    /* make a new block record, and add it to the end of the list */
196423a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
196523a0898aSmrg    if (!blockrec)
196623a0898aSmrg	return AllocError;
196723a0898aSmrg    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
196823a0898aSmrg    blockedglyph->pfont = pfont;
196923a0898aSmrg    blockedglyph->num_expected_ranges = nranges;
197023a0898aSmrg    /* Assumption: it's our job to free ranges */
197123a0898aSmrg    blockedglyph->expected_ranges = ranges;
197223a0898aSmrg    blockedglyph->clients_depending = (FSClientsDependingPtr)0;
197323a0898aSmrg
197423a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
197523a0898aSmrg    {
197623a0898aSmrg	_fs_pending_reply (conn);
197723a0898aSmrg	return Suspended;
197823a0898aSmrg    }
197923a0898aSmrg
198023a0898aSmrg    /* send the request */
198123a0898aSmrg    req.reqType = FS_QueryXBitmaps16;
198223a0898aSmrg    req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
198323a0898aSmrg    req.format = pfont->format;
198423a0898aSmrg    if (pfont->info.terminalFont)
198523a0898aSmrg	req.format = (req.format & ~(BitmapFormatImageRectMask)) |
198623a0898aSmrg		     BitmapFormatImageRectMax;
198723a0898aSmrg    req.range = TRUE;
198823a0898aSmrg    /* each range takes up 4 bytes */
198923a0898aSmrg    req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
199023a0898aSmrg    req.num_ranges = nranges * 2;	/* protocol wants count of fsChar2bs */
199123a0898aSmrg    _fs_add_req_log(conn, FS_QueryXBitmaps16);
199223a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
199323a0898aSmrg
199423a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
199523a0898aSmrg
199623a0898aSmrg    /* Send ranges to the server... pack into a char array by hand
199723a0898aSmrg       to avoid structure-packing portability problems and to
199823a0898aSmrg       handle swapping for version1 protocol */
199923a0898aSmrg    if (nranges)
200023a0898aSmrg    {
200123a0898aSmrg#define RANGE_BUFFER_SIZE 64
200223a0898aSmrg#define RANGE_BUFFER_SIZE_MASK 63
200323a0898aSmrg	int i;
200423a0898aSmrg	char range_buffer[RANGE_BUFFER_SIZE * 4];
200523a0898aSmrg	char *range_buffer_p;
200623a0898aSmrg
200723a0898aSmrg	range_buffer_p = range_buffer;
200823a0898aSmrg	for (i = 0; i < nranges;)
200923a0898aSmrg	{
201023a0898aSmrg	    if (conn->fsMajorVersion > 1)
201123a0898aSmrg	    {
201223a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_high;
201323a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_low;
201423a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_high;
201523a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_low;
201623a0898aSmrg	    }
201723a0898aSmrg	    else
201823a0898aSmrg	    {
201923a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_low;
202023a0898aSmrg		*range_buffer_p++ = ranges[i].min_char_high;
202123a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_low;
202223a0898aSmrg		*range_buffer_p++ = ranges[i].max_char_high;
202323a0898aSmrg	    }
202423a0898aSmrg
202523a0898aSmrg	    if (!(++i & RANGE_BUFFER_SIZE_MASK))
202623a0898aSmrg	    {
202723a0898aSmrg		_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
202823a0898aSmrg		range_buffer_p = range_buffer;
202923a0898aSmrg	    }
203023a0898aSmrg	}
203123a0898aSmrg	if (i &= RANGE_BUFFER_SIZE_MASK)
203223a0898aSmrg	    _fs_write(conn, range_buffer, i * 4);
203323a0898aSmrg    }
203423a0898aSmrg
203523a0898aSmrg    _fs_prepare_for_reply (conn);
203623a0898aSmrg    return Suspended;
203723a0898aSmrg}
203823a0898aSmrg
203923a0898aSmrg
204023a0898aSmrgextern pointer serverClient;	/* This could be any number that
204123a0898aSmrg				   doesn't conflict with existing
204223a0898aSmrg				   client values. */
204323a0898aSmrg
204423a0898aSmrgstatic int
204523a0898aSmrg_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
204623a0898aSmrg		unsigned int nchars, int item_size, unsigned char *data)
204723a0898aSmrg{
204823a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) pfont->fpe->private;
204923a0898aSmrg    int			    nranges = 0;
205023a0898aSmrg    fsRange		    *ranges = NULL;
205123a0898aSmrg    int			    res;
205223a0898aSmrg    FSBlockDataPtr	    blockrec;
205323a0898aSmrg    FSBlockedGlyphPtr	    blockedglyph;
205423a0898aSmrg    FSClientsDependingPtr   *clients_depending = NULL;
205523a0898aSmrg    int			    err;
205623a0898aSmrg
205723a0898aSmrg    /* see if the result is already there */
205823a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
205923a0898aSmrg    {
206023a0898aSmrg	if (blockrec->type == FS_LOAD_GLYPHS)
206123a0898aSmrg	{
206223a0898aSmrg	    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
206323a0898aSmrg	    if (blockedglyph->pfont == pfont)
206423a0898aSmrg	    {
206523a0898aSmrg		/* Look for this request */
206623a0898aSmrg		if (blockrec->client == client)
206723a0898aSmrg		{
206823a0898aSmrg		    err = blockrec->errcode;
206923a0898aSmrg		    if (err == StillWorking)
207023a0898aSmrg			return Suspended;
207123a0898aSmrg		    _fs_signal_clients_depending(&blockedglyph->clients_depending);
207223a0898aSmrg		    _fs_remove_block_rec(conn, blockrec);
207323a0898aSmrg		    return err;
207423a0898aSmrg		}
207523a0898aSmrg		/* We've found an existing LoadGlyphs blockrec for this
207623a0898aSmrg		   font but for another client.  Rather than build a
207723a0898aSmrg		   blockrec for it now (which entails some complex
207823a0898aSmrg		   maintenance), we'll add it to a queue of clients to
207923a0898aSmrg		   be signalled when the existing LoadGlyphs is
208023a0898aSmrg		   completed.  */
208123a0898aSmrg		clients_depending = &blockedglyph->clients_depending;
208223a0898aSmrg		break;
208323a0898aSmrg	    }
208423a0898aSmrg	}
208523a0898aSmrg	else if (blockrec->type == FS_OPEN_FONT)
208623a0898aSmrg	{
208723a0898aSmrg	    FSBlockedFontPtr bfont;
208823a0898aSmrg	    bfont = (FSBlockedFontPtr) blockrec->data;
208923a0898aSmrg	    if (bfont->pfont == pfont)
209023a0898aSmrg	    {
209123a0898aSmrg		/*
209223a0898aSmrg		 * An OpenFont is pending for this font, this must
209323a0898aSmrg		 * be from a reopen attempt, so finish the open
209423a0898aSmrg		 * attempt and retry the LoadGlyphs
209523a0898aSmrg		 */
209623a0898aSmrg		if (blockrec->client == client)
209723a0898aSmrg		{
209823a0898aSmrg		    err = blockrec->errcode;
209923a0898aSmrg		    if (err == StillWorking)
210023a0898aSmrg			return Suspended;
210123a0898aSmrg
210223a0898aSmrg		    _fs_signal_clients_depending(&bfont->clients_depending);
210323a0898aSmrg		    _fs_remove_block_rec(conn, blockrec);
210423a0898aSmrg		    if (err != Successful)
210523a0898aSmrg			return err;
210623a0898aSmrg		    break;
210723a0898aSmrg		}
210823a0898aSmrg		/* We've found an existing OpenFont blockrec for this
210923a0898aSmrg		   font but for another client.  Rather than build a
211023a0898aSmrg		   blockrec for it now (which entails some complex
211123a0898aSmrg		   maintenance), we'll add it to a queue of clients to
211223a0898aSmrg		   be signalled when the existing OpenFont is
211323a0898aSmrg		   completed.  */
211423a0898aSmrg		if (blockrec->errcode == StillWorking)
211523a0898aSmrg		{
211623a0898aSmrg		    clients_depending = &bfont->clients_depending;
211723a0898aSmrg		    break;
211823a0898aSmrg		}
211923a0898aSmrg	    }
212023a0898aSmrg	}
212123a0898aSmrg    }
212223a0898aSmrg
212323a0898aSmrg    /*
212423a0898aSmrg     * see if the desired glyphs already exist, and return Successful if they
212523a0898aSmrg     * do, otherwise build up character range/character string
212623a0898aSmrg     */
212723a0898aSmrg    res = fs_build_range(pfont, range_flag, nchars, item_size, data,
212823a0898aSmrg			 &nranges, &ranges);
212923a0898aSmrg
213023a0898aSmrg    switch (res)
213123a0898aSmrg    {
213223a0898aSmrg	case AccessDone:
213323a0898aSmrg	    return Successful;
213423a0898aSmrg
213523a0898aSmrg	case Successful:
213623a0898aSmrg	    break;
213723a0898aSmrg
213823a0898aSmrg	default:
213923a0898aSmrg	    return res;
214023a0898aSmrg    }
214123a0898aSmrg
214223a0898aSmrg    /*
214323a0898aSmrg     * If clients_depending is not null, this request must wait for
214423a0898aSmrg     * some prior request(s) to complete.
214523a0898aSmrg     */
214623a0898aSmrg    if (clients_depending)
214723a0898aSmrg    {
214823a0898aSmrg	/* Since we're not ready to send the load_glyphs request yet,
214923a0898aSmrg	   clean up the damage (if any) caused by the fs_build_range()
215023a0898aSmrg	   call. */
215123a0898aSmrg	if (nranges)
215223a0898aSmrg	{
215323a0898aSmrg	    _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
21547f7f5e4eSmrg	    free(ranges);
215523a0898aSmrg	}
215623a0898aSmrg	return _fs_add_clients_depending(clients_depending, client);
215723a0898aSmrg    }
215823a0898aSmrg
215923a0898aSmrg    /*
216023a0898aSmrg     * If fsd->generation != conn->generation, the font has been closed
216123a0898aSmrg     * due to a lost connection.  We will reopen it, which will result
216223a0898aSmrg     * in one of three things happening:
216323a0898aSmrg     *	 1) The open will succeed and obtain the same font.  Life
216423a0898aSmrg     *	    is wonderful.
216523a0898aSmrg     *	 2) The open will fail.  There is code above to recognize this
216623a0898aSmrg     *	    and flunk the LoadGlyphs request.  The client might not be
216723a0898aSmrg     *	    thrilled.
216823a0898aSmrg     *	 3) Worst case: the open will succeed but the font we open will
216923a0898aSmrg     *	    be different.  The fs_read_query_info() procedure attempts
217023a0898aSmrg     *	    to detect this by comparing the existing metrics and
217123a0898aSmrg     *	    properties against those of the reopened font... if they
217223a0898aSmrg     *	    don't match, we flunk the reopen, which eventually results
217323a0898aSmrg     *	    in flunking the LoadGlyphs request.  We could go a step
217423a0898aSmrg     *	    further and compare the extents, but this should be
217523a0898aSmrg     *	    sufficient.
217623a0898aSmrg     */
217723a0898aSmrg    if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
217823a0898aSmrg    {
217923a0898aSmrg	/* Since we're not ready to send the load_glyphs request yet,
218023a0898aSmrg	   clean up the damage caused by the fs_build_range() call. */
218123a0898aSmrg	_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
21827f7f5e4eSmrg	free(ranges);
218323a0898aSmrg
218423a0898aSmrg	/* Now try to reopen the font. */
218523a0898aSmrg	return fs_send_open_font(client, pfont->fpe,
218623a0898aSmrg				 (Mask)FontReopen, (char *)0, 0,
218723a0898aSmrg				 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
218823a0898aSmrg				 (XID)0, &pfont);
218923a0898aSmrg    }
219023a0898aSmrg
219123a0898aSmrg    return fs_send_load_glyphs(client, pfont, nranges, ranges);
219223a0898aSmrg}
219323a0898aSmrg
219423a0898aSmrgint
219523a0898aSmrgfs_load_all_glyphs(FontPtr pfont)
219623a0898aSmrg{
219723a0898aSmrg    int		err;
219823a0898aSmrg    FSFpePtr	conn = (FSFpePtr) pfont->fpe->private;
219923a0898aSmrg
220023a0898aSmrg    /*
220123a0898aSmrg     * The purpose of this procedure is to load all glyphs in the event
220223a0898aSmrg     * that we're dealing with someone who doesn't understand the finer
220323a0898aSmrg     * points of glyph caching...  it is called from _fs_get_glyphs() if
220423a0898aSmrg     * the latter is called to get glyphs that have not yet been loaded.
220523a0898aSmrg     * We assume that the caller will not know how to handle a return
220623a0898aSmrg     * value of Suspended (usually the case for a GetGlyphs() caller),
220723a0898aSmrg     * so this procedure hangs around, freezing the server, for the
220823a0898aSmrg     * request to complete.  This is an unpleasant kluge called to
220923a0898aSmrg     * perform an unpleasant job that, we hope, will never be required.
221023a0898aSmrg     */
221123a0898aSmrg
221223a0898aSmrg    while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) ==
221323a0898aSmrg	   Suspended)
221423a0898aSmrg    {
221523a0898aSmrg	if (fs_await_reply (conn) != FSIO_READY)
221623a0898aSmrg	{
221723a0898aSmrg	    /* Get rid of blockrec */
221823a0898aSmrg	    fs_client_died(serverClient, pfont->fpe);
221923a0898aSmrg	    err = BadCharRange;
222023a0898aSmrg	    break;
222123a0898aSmrg	}
222223a0898aSmrg	fs_read_reply (pfont->fpe, serverClient);
222323a0898aSmrg    }
222423a0898aSmrg    return err;
222523a0898aSmrg}
222623a0898aSmrg
222723a0898aSmrgstatic int
222823a0898aSmrgfs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
222923a0898aSmrg{
223023a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
223123a0898aSmrg    FSBlockedListPtr	blist = (FSBlockedListPtr) blockrec->data;
223223a0898aSmrg    fsListFontsReply	*rep;
223323a0898aSmrg    char		*data;
223423a0898aSmrg    int			length,
223523a0898aSmrg			i,
223623a0898aSmrg			ret;
223723a0898aSmrg    int			err;
223823a0898aSmrg
223923a0898aSmrg    rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
224023a0898aSmrg    if (!rep || rep->type == FS_Error)
224123a0898aSmrg    {
224223a0898aSmrg	if (ret == FSIO_BLOCK)
224323a0898aSmrg	    return StillWorking;
224423a0898aSmrg	if (rep)
224523a0898aSmrg	    _fs_done_read (conn, rep->length << 2);
224623a0898aSmrg	return AllocError;
224723a0898aSmrg    }
224823a0898aSmrg    data = (char *) rep + SIZEOF (fsListFontsReply);
224923a0898aSmrg
225023a0898aSmrg    err = Successful;
225123a0898aSmrg    /* copy data into FontPathRecord */
225223a0898aSmrg    for (i = 0; i < rep->nFonts; i++)
225323a0898aSmrg    {
225423a0898aSmrg	length = *(unsigned char *)data++;
225523a0898aSmrg	err = AddFontNamesName(blist->names, data, length);
225623a0898aSmrg	if (err != Successful)
225723a0898aSmrg	    break;
225823a0898aSmrg	data += length;
225923a0898aSmrg    }
226023a0898aSmrg    _fs_done_read (conn, rep->length << 2);
226123a0898aSmrg    return err;
226223a0898aSmrg}
226323a0898aSmrg
226423a0898aSmrgstatic int
226523a0898aSmrgfs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern,
226623a0898aSmrg		   int patlen, int maxnames, FontNamesPtr newnames)
226723a0898aSmrg{
226823a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
226923a0898aSmrg    FSBlockDataPtr	blockrec;
227023a0898aSmrg    FSBlockedListPtr	blockedlist;
227123a0898aSmrg    fsListFontsReq	req;
227223a0898aSmrg
227323a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
227423a0898aSmrg	return BadFontName;
227523a0898aSmrg
227623a0898aSmrg    /* make a new block record, and add it to the end of the list */
227723a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
227823a0898aSmrg    if (!blockrec)
227923a0898aSmrg	return AllocError;
228023a0898aSmrg    blockedlist = (FSBlockedListPtr) blockrec->data;
228123a0898aSmrg    blockedlist->names = newnames;
228223a0898aSmrg
228323a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
228423a0898aSmrg    {
228523a0898aSmrg	_fs_pending_reply (conn);
228623a0898aSmrg	return Suspended;
228723a0898aSmrg    }
228823a0898aSmrg
228923a0898aSmrg    _fs_client_access (conn, client, FALSE);
229023a0898aSmrg    _fs_client_resolution(conn);
229123a0898aSmrg
229223a0898aSmrg    /* send the request */
229323a0898aSmrg    req.reqType = FS_ListFonts;
22947f7f5e4eSmrg    req.pad = 0;
229523a0898aSmrg    req.maxNames = maxnames;
229623a0898aSmrg    req.nbytes = patlen;
229723a0898aSmrg    req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
229823a0898aSmrg    _fs_add_req_log(conn, FS_ListFonts);
229923a0898aSmrg    _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
230023a0898aSmrg    _fs_write_pad(conn, (char *) pattern, patlen);
230123a0898aSmrg
230223a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
230323a0898aSmrg
230423a0898aSmrg#ifdef NCD
230523a0898aSmrg    if (configData.ExtendedFontDiags) {
230623a0898aSmrg	char        buf[256];
230723a0898aSmrg
230823a0898aSmrg	memcpy(buf, pattern, MIN(256, patlen));
230923a0898aSmrg	buf[MIN(256, patlen)] = '\0';
231023a0898aSmrg	printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
231123a0898aSmrg	       buf, fpe->name);
231223a0898aSmrg    }
231323a0898aSmrg#endif
231423a0898aSmrg
231523a0898aSmrg    _fs_prepare_for_reply (conn);
231623a0898aSmrg    return Suspended;
231723a0898aSmrg}
231823a0898aSmrg
231923a0898aSmrgstatic int
232023a0898aSmrgfs_list_fonts(pointer client, FontPathElementPtr fpe,
232123a0898aSmrg	      char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
232223a0898aSmrg{
232323a0898aSmrg    FSFpePtr		conn = (FSFpePtr) fpe->private;
232423a0898aSmrg    FSBlockDataPtr	blockrec;
232523a0898aSmrg    int			err;
232623a0898aSmrg
232723a0898aSmrg    /* see if the result is already there */
232823a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
232923a0898aSmrg    {
233023a0898aSmrg	if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
233123a0898aSmrg	{
233223a0898aSmrg	    err = blockrec->errcode;
233323a0898aSmrg	    if (err == StillWorking)
233423a0898aSmrg		return Suspended;
233523a0898aSmrg	    _fs_remove_block_rec(conn, blockrec);
233623a0898aSmrg	    return err;
233723a0898aSmrg	}
233823a0898aSmrg    }
233923a0898aSmrg
234023a0898aSmrg    /* didn't find waiting record, so send a new one */
234123a0898aSmrg    return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
234223a0898aSmrg}
234323a0898aSmrg
234423a0898aSmrg/*
234523a0898aSmrg * Read a single list info reply and restart for the next reply
234623a0898aSmrg */
234723a0898aSmrgstatic int
234823a0898aSmrgfs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
234923a0898aSmrg{
235023a0898aSmrg    FSBlockedListInfoPtr	binfo = (FSBlockedListInfoPtr) blockrec->data;
235123a0898aSmrg    fsListFontsWithXInfoReply	*rep;
235223a0898aSmrg    char			*buf;
235323a0898aSmrg    FSFpePtr			conn = (FSFpePtr) fpe->private;
235423a0898aSmrg    fsPropInfo			*pi;
235523a0898aSmrg    fsPropOffset		*po;
235623a0898aSmrg    pointer			pd;
235723a0898aSmrg    int				ret;
235823a0898aSmrg    int				err;
235923a0898aSmrg
236023a0898aSmrg    /* clean up anything from the last trip */
236123a0898aSmrg    _fs_free_props (&binfo->info);
236223a0898aSmrg
236323a0898aSmrg    rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
236423a0898aSmrg    if (!rep || rep->type == FS_Error)
236523a0898aSmrg    {
236623a0898aSmrg	if (ret == FSIO_BLOCK)
236723a0898aSmrg	    return StillWorking;
236823a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
236923a0898aSmrg	err = AllocError;
237023a0898aSmrg	goto done;
237123a0898aSmrg    }
237223a0898aSmrg    /*
237323a0898aSmrg     * Normal termination -- the list ends with a name of length 0
237423a0898aSmrg     */
237523a0898aSmrg    if (rep->nameLength == 0)
237623a0898aSmrg    {
237723a0898aSmrg#ifdef DEBUG
237823a0898aSmrg	fprintf (stderr, "fs_read_list_info done\n");
237923a0898aSmrg#endif
238023a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
238123a0898aSmrg	err = BadFontName;
238223a0898aSmrg	goto done;
238323a0898aSmrg    }
238423a0898aSmrg
238523a0898aSmrg    buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
238623a0898aSmrg
238723a0898aSmrg    /*
238823a0898aSmrg     * The original FS implementation didn't match
238923a0898aSmrg     * the spec, version 1 was respecified to match the FS.
239023a0898aSmrg     * Version 2 matches the original intent
239123a0898aSmrg     */
239223a0898aSmrg    if (conn->fsMajorVersion <= 1)
239323a0898aSmrg    {
239423a0898aSmrg	memcpy (binfo->name, buf, rep->nameLength);
239523a0898aSmrg	buf += _fs_pad_length (rep->nameLength);
239623a0898aSmrg    }
239723a0898aSmrg    pi = (fsPropInfo *) buf;
239823a0898aSmrg    buf += SIZEOF (fsPropInfo);
239923a0898aSmrg    po = (fsPropOffset *) buf;
240023a0898aSmrg    buf += pi->num_offsets * SIZEOF (fsPropOffset);
240123a0898aSmrg    pd = (pointer) buf;
240223a0898aSmrg    buf += pi->data_len;
240323a0898aSmrg    if (conn->fsMajorVersion > 1)
240423a0898aSmrg    {
240523a0898aSmrg	memcpy (binfo->name, buf, rep->nameLength);
240623a0898aSmrg	buf += _fs_pad_length (rep->nameLength);
240723a0898aSmrg    }
240823a0898aSmrg
240923a0898aSmrg#ifdef DEBUG
241023a0898aSmrg    binfo->name[rep->nameLength] = '\0';
241123a0898aSmrg    fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
241223a0898aSmrg#endif
241323a0898aSmrg    err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
241423a0898aSmrg    if (err != Successful)
241523a0898aSmrg    {
241623a0898aSmrg	binfo->status = FS_LFWI_FINISHED;
241723a0898aSmrg	goto done;
241823a0898aSmrg    }
241923a0898aSmrg    binfo->namelen = rep->nameLength;
242023a0898aSmrg    binfo->remaining = rep->nReplies;
242123a0898aSmrg
242223a0898aSmrg    binfo->status = FS_LFWI_REPLY;
242323a0898aSmrg
242423a0898aSmrg    /* disable this font server until we've processed this response */
242523a0898aSmrg    _fs_unmark_block (conn, FS_COMPLETE_REPLY);
242623a0898aSmrg    FD_CLR(conn->fs_fd, &_fs_fd_mask);
242723a0898aSmrgdone:
242823a0898aSmrg    _fs_done_read (conn, rep->length << 2);
242923a0898aSmrg    return err;
243023a0898aSmrg}
243123a0898aSmrg
243223a0898aSmrg/* ARGSUSED */
243323a0898aSmrgstatic int
243423a0898aSmrgfs_start_list_with_info(pointer client, FontPathElementPtr fpe,
243523a0898aSmrg			char *pattern, int len, int maxnames, pointer *pdata)
243623a0898aSmrg{
243723a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
243823a0898aSmrg    FSBlockDataPtr	    blockrec;
243923a0898aSmrg    FSBlockedListInfoPtr    binfo;
244023a0898aSmrg    fsListFontsWithXInfoReq req;
244123a0898aSmrg
244223a0898aSmrg    if (conn->blockState & FS_GIVE_UP)
244323a0898aSmrg	return BadFontName;
244423a0898aSmrg
244523a0898aSmrg    /* make a new block record, and add it to the end of the list */
244623a0898aSmrg    blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
244723a0898aSmrg    if (!blockrec)
244823a0898aSmrg	return AllocError;
244923a0898aSmrg
245023a0898aSmrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
245123a0898aSmrg    bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
245223a0898aSmrg    binfo->status = FS_LFWI_WAITING;
245323a0898aSmrg
245423a0898aSmrg    if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
245523a0898aSmrg    {
245623a0898aSmrg	_fs_pending_reply (conn);
245723a0898aSmrg	return Suspended;
245823a0898aSmrg    }
245923a0898aSmrg
246023a0898aSmrg    _fs_client_access (conn, client, FALSE);
246123a0898aSmrg    _fs_client_resolution(conn);
246223a0898aSmrg
246323a0898aSmrg    /* send the request */
246423a0898aSmrg    req.reqType = FS_ListFontsWithXInfo;
24657f7f5e4eSmrg    req.pad = 0;
246623a0898aSmrg    req.maxNames = maxnames;
246723a0898aSmrg    req.nbytes = len;
246823a0898aSmrg    req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
246923a0898aSmrg    _fs_add_req_log(conn, FS_ListFontsWithXInfo);
247023a0898aSmrg    (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
247123a0898aSmrg    (void) _fs_write_pad(conn, pattern, len);
247223a0898aSmrg
247323a0898aSmrg    blockrec->sequenceNumber = conn->current_seq;
247423a0898aSmrg
247523a0898aSmrg#ifdef NCD
247623a0898aSmrg    if (configData.ExtendedFontDiags) {
247723a0898aSmrg	char        buf[256];
247823a0898aSmrg
247923a0898aSmrg	memcpy(buf, pattern, MIN(256, len));
248023a0898aSmrg	buf[MIN(256, len)] = '\0';
248123a0898aSmrg	printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
248223a0898aSmrg	       buf, fpe->name);
248323a0898aSmrg    }
248423a0898aSmrg#endif
248523a0898aSmrg
248623a0898aSmrg    _fs_prepare_for_reply (conn);
248723a0898aSmrg    return Successful;
248823a0898aSmrg}
248923a0898aSmrg
249023a0898aSmrg/* ARGSUSED */
249123a0898aSmrgstatic int
249223a0898aSmrgfs_next_list_with_info(pointer client, FontPathElementPtr fpe,
249323a0898aSmrg		       char **namep, int *namelenp,
249423a0898aSmrg		       FontInfoPtr *pFontInfo, int *numFonts,
249523a0898aSmrg		       pointer private)
249623a0898aSmrg{
249723a0898aSmrg    FSFpePtr		    conn = (FSFpePtr) fpe->private;
249823a0898aSmrg    FSBlockDataPtr	    blockrec;
249923a0898aSmrg    FSBlockedListInfoPtr    binfo;
250023a0898aSmrg    int			    err;
250123a0898aSmrg
250223a0898aSmrg    /* see if the result is already there */
250323a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
250423a0898aSmrg	if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
250523a0898aSmrg	    break;
250623a0898aSmrg
250723a0898aSmrg    if (!blockrec)
250823a0898aSmrg    {
250923a0898aSmrg	/* The only good reason for not finding a blockrec would be if
251023a0898aSmrg	   disconnect/reconnect to the font server wiped it out and the
251123a0898aSmrg	   code that called us didn't do the right thing to create
251223a0898aSmrg	   another one.  Under those circumstances, we need to return an
251323a0898aSmrg	   error to prevent that code from attempting to interpret the
251423a0898aSmrg	   information we don't return.  */
251523a0898aSmrg	return BadFontName;
251623a0898aSmrg    }
251723a0898aSmrg
251823a0898aSmrg    binfo = (FSBlockedListInfoPtr) blockrec->data;
251923a0898aSmrg
252023a0898aSmrg    if (binfo->status == FS_LFWI_WAITING)
252123a0898aSmrg	return Suspended;
252223a0898aSmrg
252323a0898aSmrg    *namep = binfo->name;
252423a0898aSmrg    *namelenp = binfo->namelen;
252523a0898aSmrg    *pFontInfo = &binfo->info;
252623a0898aSmrg    *numFonts = binfo->remaining;
252723a0898aSmrg
252823a0898aSmrg    /* Restart reply processing from this font server */
252923a0898aSmrg    FD_SET(conn->fs_fd, &_fs_fd_mask);
253023a0898aSmrg    if (fs_reply_ready (conn))
253123a0898aSmrg	_fs_mark_block (conn, FS_COMPLETE_REPLY);
253223a0898aSmrg
253323a0898aSmrg    err = blockrec->errcode;
253423a0898aSmrg    switch (binfo->status) {
253523a0898aSmrg    case FS_LFWI_FINISHED:
253623a0898aSmrg	_fs_remove_block_rec(conn, blockrec);
253723a0898aSmrg	break;
253823a0898aSmrg    case FS_LFWI_REPLY:
253923a0898aSmrg	binfo->status = FS_LFWI_WAITING;
254023a0898aSmrg	blockrec->errcode = StillWorking;
254123a0898aSmrg	conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
254223a0898aSmrg	_fs_mark_block (conn, FS_PENDING_REPLY);
254323a0898aSmrg	break;
254423a0898aSmrg    }
254523a0898aSmrg
254623a0898aSmrg    return err;
254723a0898aSmrg}
254823a0898aSmrg
254923a0898aSmrg/*
255023a0898aSmrg * Called when client exits
255123a0898aSmrg */
255223a0898aSmrg
255323a0898aSmrgstatic void
255423a0898aSmrgfs_client_died(pointer client, FontPathElementPtr fpe)
255523a0898aSmrg{
255623a0898aSmrg    FSFpePtr	    conn = (FSFpePtr) fpe->private;
255723a0898aSmrg    FSBlockDataPtr  blockrec,
255823a0898aSmrg		    depending;
255923a0898aSmrg    FSClientPtr	    *prev, cur;
256023a0898aSmrg    fsFreeACReq	    freeac;
256123a0898aSmrg
256223a0898aSmrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
256323a0898aSmrg    {
256423a0898aSmrg	if (cur->client == client) {
256523a0898aSmrg	    freeac.reqType = FS_FreeAC;
25667f7f5e4eSmrg	    freeac.pad = 0;
256723a0898aSmrg	    freeac.id = cur->acid;
256823a0898aSmrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
256923a0898aSmrg	    _fs_add_req_log(conn, FS_FreeAC);
257023a0898aSmrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
257123a0898aSmrg	    *prev = cur->next;
25727f7f5e4eSmrg	    free (cur);
257323a0898aSmrg	    break;
257423a0898aSmrg	}
257523a0898aSmrg    }
257623a0898aSmrg    /* find a pending requests */
257723a0898aSmrg    for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
257823a0898aSmrg	if (blockrec->client == client)
257923a0898aSmrg	    break;
258023a0898aSmrg
258123a0898aSmrg    if (!blockrec)
258223a0898aSmrg	return;
258323a0898aSmrg
258423a0898aSmrg    /* replace the client pointers in this block rec with the chained one */
258523a0898aSmrg    if ((depending = blockrec->depending))
258623a0898aSmrg    {
258723a0898aSmrg	blockrec->client = depending->client;
258823a0898aSmrg	blockrec->depending = depending->depending;
258923a0898aSmrg	blockrec = depending;
259023a0898aSmrg    }
259123a0898aSmrg    fs_abort_blockrec(conn, blockrec);
259223a0898aSmrg}
259323a0898aSmrg
259423a0898aSmrgstatic void
259523a0898aSmrg_fs_client_access (FSFpePtr conn, pointer client, Bool sync)
259623a0898aSmrg{
259723a0898aSmrg    FSClientPtr	*prev,	    cur;
259823a0898aSmrg    fsCreateACReq	    crac;
259923a0898aSmrg    fsSetAuthorizationReq   setac;
260023a0898aSmrg    char		    *authorizations;
260123a0898aSmrg    int			    authlen;
260223a0898aSmrg    Bool		    new_cur = FALSE;
26037f7f5e4eSmrg    char		    padding[4] = { 0, 0, 0, 0 };
260423a0898aSmrg
260523a0898aSmrg#ifdef DEBUG
260623a0898aSmrg    if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
260723a0898aSmrg    {
260823a0898aSmrg	fprintf (stderr, "Sending requests without a connection\n");
260923a0898aSmrg    }
261023a0898aSmrg#endif
261123a0898aSmrg    for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
261223a0898aSmrg    {
261323a0898aSmrg	if (cur->client == client)
261423a0898aSmrg	{
261523a0898aSmrg	    if (prev != &conn->clients)
261623a0898aSmrg	    {
261723a0898aSmrg		*prev = cur->next;
261823a0898aSmrg		cur->next = conn->clients;
261923a0898aSmrg		conn->clients = cur;
262023a0898aSmrg	    }
262123a0898aSmrg	    break;
262223a0898aSmrg	}
262323a0898aSmrg    }
262423a0898aSmrg    if (!cur)
262523a0898aSmrg    {
26267f7f5e4eSmrg	cur = malloc (sizeof (FSClientRec));
262723a0898aSmrg	if (!cur)
262823a0898aSmrg	    return;
262923a0898aSmrg	cur->client = client;
263023a0898aSmrg	cur->next = conn->clients;
263123a0898aSmrg	conn->clients = cur;
263223a0898aSmrg	cur->acid = GetNewFontClientID ();
263323a0898aSmrg	new_cur = TRUE;
263423a0898aSmrg    }
263523a0898aSmrg    if (new_cur || cur->auth_generation != client_auth_generation(client))
263623a0898aSmrg    {
263723a0898aSmrg	if (!new_cur)
263823a0898aSmrg	{
263923a0898aSmrg	    fsFreeACReq	freeac;
264023a0898aSmrg	    freeac.reqType = FS_FreeAC;
26417f7f5e4eSmrg	    freeac.pad = 0;
264223a0898aSmrg	    freeac.id = cur->acid;
264323a0898aSmrg	    freeac.length = sizeof (fsFreeACReq) >> 2;
264423a0898aSmrg	    _fs_add_req_log(conn, FS_FreeAC);
264523a0898aSmrg	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
264623a0898aSmrg	}
264723a0898aSmrg	crac.reqType = FS_CreateAC;
264823a0898aSmrg	crac.num_auths = set_font_authorizations(&authorizations, &authlen,
264923a0898aSmrg						 client);
26507f7f5e4eSmrg	/* Work around bug in xfs versions up through modular release 1.0.8
26517f7f5e4eSmrg	   which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
26527f7f5e4eSmrg	if (crac.num_auths == 0) {
26537f7f5e4eSmrg	    authorizations = padding;
26547f7f5e4eSmrg	    authlen = 4;
26557f7f5e4eSmrg	} else {
26567f7f5e4eSmrg	    authlen = (authlen + 3) & ~0x3;
26577f7f5e4eSmrg	}
265823a0898aSmrg	crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
265923a0898aSmrg	crac.acid = cur->acid;
266023a0898aSmrg	_fs_add_req_log(conn, FS_CreateAC);
266123a0898aSmrg	_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
266223a0898aSmrg	_fs_write(conn, authorizations, authlen);
266323a0898aSmrg	/* ignore reply; we don't even care about it */
266423a0898aSmrg	conn->curacid = 0;
266523a0898aSmrg	cur->auth_generation = client_auth_generation(client);
266623a0898aSmrg    }
266723a0898aSmrg    if (conn->curacid != cur->acid)
266823a0898aSmrg    {
266923a0898aSmrg    	setac.reqType = FS_SetAuthorization;
26707f7f5e4eSmrg	setac.pad = 0;
267123a0898aSmrg    	setac.length = sizeof (fsSetAuthorizationReq) >> 2;
267223a0898aSmrg    	setac.id = cur->acid;
267323a0898aSmrg    	_fs_add_req_log(conn, FS_SetAuthorization);
267423a0898aSmrg    	_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
267523a0898aSmrg	conn->curacid = cur->acid;
267623a0898aSmrg    }
267723a0898aSmrg}
267823a0898aSmrg
267923a0898aSmrg/*
268023a0898aSmrg * Poll a pending connect
268123a0898aSmrg */
268223a0898aSmrg
268323a0898aSmrgstatic int
268423a0898aSmrg_fs_check_connect (FSFpePtr conn)
268523a0898aSmrg{
268623a0898aSmrg    int	    ret;
268723a0898aSmrg
268823a0898aSmrg    ret = _fs_poll_connect (conn->trans_conn, 0);
268923a0898aSmrg    switch (ret) {
269023a0898aSmrg    case FSIO_READY:
269123a0898aSmrg	conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
269223a0898aSmrg	FD_SET (conn->fs_fd, &_fs_fd_mask);
269323a0898aSmrg	break;
269423a0898aSmrg    case FSIO_BLOCK:
269523a0898aSmrg	break;
269623a0898aSmrg    }
269723a0898aSmrg    return ret;
269823a0898aSmrg}
269923a0898aSmrg
270023a0898aSmrg/*
270123a0898aSmrg * Return an FSIO status while waiting for the completed connection
270223a0898aSmrg * reply to arrive
270323a0898aSmrg */
270423a0898aSmrg
270523a0898aSmrgstatic fsConnSetup *
270623a0898aSmrg_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
270723a0898aSmrg{
270823a0898aSmrg    int			ret;
270923a0898aSmrg    char		*data;
271023a0898aSmrg    int			headlen;
271123a0898aSmrg    int			len;
271223a0898aSmrg    fsConnSetup		*setup;
271323a0898aSmrg    fsConnSetupAccept	*accept;
271423a0898aSmrg
271523a0898aSmrg    ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
271623a0898aSmrg    if (ret != FSIO_READY)
271723a0898aSmrg    {
271823a0898aSmrg	*error = ret;
271923a0898aSmrg	return 0;
272023a0898aSmrg    }
272123a0898aSmrg
272223a0898aSmrg    setup = (fsConnSetup *) data;
272323a0898aSmrg    if (setup->major_version > FS_PROTOCOL)
272423a0898aSmrg    {
272523a0898aSmrg	*error = FSIO_ERROR;
272623a0898aSmrg	return 0;
272723a0898aSmrg    }
272823a0898aSmrg
272923a0898aSmrg    headlen = (SIZEOF (fsConnSetup) +
273023a0898aSmrg	       (setup->alternate_len << 2) +
273123a0898aSmrg	       (setup->auth_len << 2));
273223a0898aSmrg    /* On anything but Success, no extra data is sent */
273323a0898aSmrg    if (setup->status != AuthSuccess)
273423a0898aSmrg    {
273523a0898aSmrg	len = headlen;
273623a0898aSmrg    }
273723a0898aSmrg    else
273823a0898aSmrg    {
273923a0898aSmrg	ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
274023a0898aSmrg	if (ret != FSIO_READY)
274123a0898aSmrg	{
274223a0898aSmrg	    *error = ret;
274323a0898aSmrg	    return 0;
274423a0898aSmrg	}
274523a0898aSmrg	setup = (fsConnSetup *) data;
274623a0898aSmrg	accept = (fsConnSetupAccept *) (data + headlen);
274723a0898aSmrg	len = headlen + (accept->length << 2);
274823a0898aSmrg    }
274923a0898aSmrg    ret = _fs_start_read (conn, len, &data);
275023a0898aSmrg    if (ret != FSIO_READY)
275123a0898aSmrg    {
275223a0898aSmrg	*error = ret;
275323a0898aSmrg	return 0;
275423a0898aSmrg    }
275523a0898aSmrg    *setup_len = len;
275623a0898aSmrg    return (fsConnSetup *) data;
275723a0898aSmrg}
275823a0898aSmrg
275923a0898aSmrgstatic int
276023a0898aSmrg_fs_send_conn_client_prefix (FSFpePtr conn)
276123a0898aSmrg{
276223a0898aSmrg    fsConnClientPrefix	req;
276323a0898aSmrg    int			endian;
276423a0898aSmrg    int			ret;
276523a0898aSmrg
276623a0898aSmrg    /* send setup prefix */
276723a0898aSmrg    endian = 1;
276823a0898aSmrg    if (*(char *) &endian)
276923a0898aSmrg	req.byteOrder = 'l';
277023a0898aSmrg    else
277123a0898aSmrg	req.byteOrder = 'B';
277223a0898aSmrg
277323a0898aSmrg    req.major_version = FS_PROTOCOL;
277423a0898aSmrg    req.minor_version = FS_PROTOCOL_MINOR;
277523a0898aSmrg
277623a0898aSmrg/* XXX add some auth info here */
277723a0898aSmrg    req.num_auths = 0;
277823a0898aSmrg    req.auth_len = 0;
277923a0898aSmrg    ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
278023a0898aSmrg    if (ret != FSIO_READY)
278123a0898aSmrg	return FSIO_ERROR;
278223a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
278323a0898aSmrg    return ret;
278423a0898aSmrg}
278523a0898aSmrg
278623a0898aSmrgstatic int
278723a0898aSmrg_fs_recv_conn_setup (FSFpePtr conn)
278823a0898aSmrg{
278923a0898aSmrg    int			ret = FSIO_ERROR;
279023a0898aSmrg    fsConnSetup		*setup;
279123a0898aSmrg    FSFpeAltPtr		alts;
279223a0898aSmrg    int			i, alt_len;
279323a0898aSmrg    int			setup_len;
279423a0898aSmrg    char		*alt_save, *alt_names;
279523a0898aSmrg
279623a0898aSmrg    setup = _fs_get_conn_setup (conn, &ret, &setup_len);
279723a0898aSmrg    if (!setup)
279823a0898aSmrg	return ret;
279923a0898aSmrg    conn->current_seq = 0;
280023a0898aSmrg    conn->fsMajorVersion = setup->major_version;
280123a0898aSmrg    /*
280223a0898aSmrg     * Create an alternate list from the initial server, but
280323a0898aSmrg     * don't chain looking for alternates.
280423a0898aSmrg     */
280523a0898aSmrg    if (conn->alternate == 0)
280623a0898aSmrg    {
280723a0898aSmrg	/*
280823a0898aSmrg	 * free any existing alternates list, allowing the list to
280923a0898aSmrg	 * be updated
281023a0898aSmrg	 */
281123a0898aSmrg	if (conn->alts)
281223a0898aSmrg	{
28137f7f5e4eSmrg	    free (conn->alts);
281423a0898aSmrg	    conn->alts = 0;
281523a0898aSmrg	    conn->numAlts = 0;
281623a0898aSmrg	}
281723a0898aSmrg	if (setup->num_alternates)
281823a0898aSmrg	{
28197f7f5e4eSmrg	    alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
28207f7f5e4eSmrg			   (setup->alternate_len << 2));
282123a0898aSmrg	    if (alts)
282223a0898aSmrg	    {
282323a0898aSmrg		alt_names = (char *) (setup + 1);
282423a0898aSmrg		alt_save = (char *) (alts + setup->num_alternates);
282523a0898aSmrg		for (i = 0; i < setup->num_alternates; i++)
282623a0898aSmrg		{
282723a0898aSmrg		    alts[i].subset = alt_names[0];
282823a0898aSmrg		    alt_len = alt_names[1];
282923a0898aSmrg		    alts[i].name = alt_save;
283023a0898aSmrg		    memcpy (alt_save, alt_names + 2, alt_len);
283123a0898aSmrg		    alt_save[alt_len] = '\0';
283223a0898aSmrg		    alt_save += alt_len + 1;
283323a0898aSmrg		    alt_names += _fs_pad_length (alt_len + 2);
283423a0898aSmrg		}
283523a0898aSmrg		conn->numAlts = setup->num_alternates;
283623a0898aSmrg		conn->alts = alts;
283723a0898aSmrg	    }
283823a0898aSmrg	}
283923a0898aSmrg    }
284023a0898aSmrg    _fs_done_read (conn, setup_len);
284123a0898aSmrg    if (setup->status != AuthSuccess)
284223a0898aSmrg	return FSIO_ERROR;
284323a0898aSmrg    return FSIO_READY;
284423a0898aSmrg}
284523a0898aSmrg
284623a0898aSmrgstatic int
284723a0898aSmrg_fs_open_server (FSFpePtr conn)
284823a0898aSmrg{
284923a0898aSmrg    int	    ret;
285023a0898aSmrg    char    *servername;
285123a0898aSmrg
285223a0898aSmrg    if (conn->alternate == 0)
285323a0898aSmrg	servername = conn->servername;
285423a0898aSmrg    else
285523a0898aSmrg	servername = conn->alts[conn->alternate-1].name;
285623a0898aSmrg    conn->trans_conn = _fs_connect (servername, &ret);
285723a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
285823a0898aSmrg    return ret;
285923a0898aSmrg}
286023a0898aSmrg
286123a0898aSmrgstatic char *
286223a0898aSmrg_fs_catalog_name (char *servername)
286323a0898aSmrg{
286423a0898aSmrg    char    *sp;
286523a0898aSmrg
286623a0898aSmrg    sp = strchr (servername, '/');
286723a0898aSmrg    if (!sp)
286823a0898aSmrg	return 0;
286923a0898aSmrg    return strrchr (sp + 1, '/');
287023a0898aSmrg}
287123a0898aSmrg
287223a0898aSmrgstatic int
287323a0898aSmrg_fs_send_init_packets (FSFpePtr conn)
287423a0898aSmrg{
287523a0898aSmrg    fsSetResolutionReq	    srreq;
287623a0898aSmrg    fsSetCataloguesReq	    screq;
287723a0898aSmrg    int			    num_cats,
287823a0898aSmrg			    clen;
287923a0898aSmrg    char		    *catalogues;
288023a0898aSmrg    char		    *cat;
288123a0898aSmrg    char		    len;
288223a0898aSmrg    char		    *end;
288323a0898aSmrg    int			    num_res;
288423a0898aSmrg    FontResolutionPtr	    res;
288523a0898aSmrg
288623a0898aSmrg#define	CATALOGUE_SEP	'+'
288723a0898aSmrg
288823a0898aSmrg    res = GetClientResolutions(&num_res);
288923a0898aSmrg    if (num_res)
289023a0898aSmrg    {
289123a0898aSmrg	srreq.reqType = FS_SetResolution;
289223a0898aSmrg	srreq.num_resolutions = num_res;
289323a0898aSmrg	srreq.length = (SIZEOF(fsSetResolutionReq) +
289423a0898aSmrg			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
289523a0898aSmrg
289623a0898aSmrg	_fs_add_req_log(conn, FS_SetResolution);
289723a0898aSmrg	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
289823a0898aSmrg	    return FSIO_ERROR;
289923a0898aSmrg	if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
290023a0898aSmrg	    return FSIO_ERROR;
290123a0898aSmrg    }
290223a0898aSmrg
290323a0898aSmrg    catalogues = 0;
290423a0898aSmrg    if (conn->alternate != 0)
290523a0898aSmrg	catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
290623a0898aSmrg    if (!catalogues)
290723a0898aSmrg	catalogues = _fs_catalog_name (conn->servername);
290823a0898aSmrg
290923a0898aSmrg    if (!catalogues)
291023a0898aSmrg    {
291123a0898aSmrg	conn->has_catalogues = FALSE;
291223a0898aSmrg	return FSIO_READY;
291323a0898aSmrg    }
291423a0898aSmrg    conn->has_catalogues = TRUE;
291523a0898aSmrg
291623a0898aSmrg    /* turn cats into counted list */
291723a0898aSmrg    catalogues++;
291823a0898aSmrg
291923a0898aSmrg    cat = catalogues;
292023a0898aSmrg    num_cats = 0;
292123a0898aSmrg    clen = 0;
292223a0898aSmrg    while (*cat)
292323a0898aSmrg    {
292423a0898aSmrg	num_cats++;
292523a0898aSmrg	end = strchr(cat, CATALOGUE_SEP);
292623a0898aSmrg	if (!end)
292723a0898aSmrg	    end = cat + strlen (cat);
292823a0898aSmrg	clen += (end - cat) + 1;	/* length byte + string */
292923a0898aSmrg	cat = end;
293023a0898aSmrg    }
293123a0898aSmrg
293223a0898aSmrg    screq.reqType = FS_SetCatalogues;
293323a0898aSmrg    screq.num_catalogues = num_cats;
293423a0898aSmrg    screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
293523a0898aSmrg
293623a0898aSmrg    _fs_add_req_log(conn, FS_SetCatalogues);
293723a0898aSmrg    if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
293823a0898aSmrg	return FSIO_ERROR;
293923a0898aSmrg
294023a0898aSmrg    while (*cat)
294123a0898aSmrg    {
294223a0898aSmrg	num_cats++;
294323a0898aSmrg	end = strchr(cat, CATALOGUE_SEP);
294423a0898aSmrg	if (!end)
294523a0898aSmrg	    end = cat + strlen (cat);
294623a0898aSmrg	len = end - cat;
294723a0898aSmrg	if (_fs_write (conn, &len, 1) != FSIO_READY)
294823a0898aSmrg	    return FSIO_ERROR;
294923a0898aSmrg	if (_fs_write (conn, cat, (int) len) != FSIO_READY)
295023a0898aSmrg	    return FSIO_ERROR;
295123a0898aSmrg	cat = end;
295223a0898aSmrg    }
295323a0898aSmrg
295423a0898aSmrg    if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
295523a0898aSmrg	return FSIO_ERROR;
295623a0898aSmrg
295723a0898aSmrg    return FSIO_READY;
295823a0898aSmrg}
295923a0898aSmrg
296023a0898aSmrgstatic int
296123a0898aSmrg_fs_send_cat_sync (FSFpePtr conn)
296223a0898aSmrg{
296323a0898aSmrg    fsListCataloguesReq	    lcreq;
296423a0898aSmrg
296523a0898aSmrg    /*
296623a0898aSmrg     * now sync up with the font server, to see if an error was generated
296723a0898aSmrg     * by a bogus catalogue
296823a0898aSmrg     */
296923a0898aSmrg    lcreq.reqType = FS_ListCatalogues;
297023a0898aSmrg    lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
297123a0898aSmrg    lcreq.maxNames = 0;
297223a0898aSmrg    lcreq.nbytes = 0;
29737f7f5e4eSmrg    lcreq.pad2 = 0;
297423a0898aSmrg    _fs_add_req_log(conn, FS_SetCatalogues);
297523a0898aSmrg    if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
297623a0898aSmrg	return FSIO_ERROR;
297723a0898aSmrg    conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
297823a0898aSmrg    return FSIO_READY;
297923a0898aSmrg}
298023a0898aSmrg
298123a0898aSmrgstatic int
298223a0898aSmrg_fs_recv_cat_sync (FSFpePtr conn)
298323a0898aSmrg{
298423a0898aSmrg    fsGenericReply  *reply;
298523a0898aSmrg    fsError	    *error;
298623a0898aSmrg    int		    err;
298723a0898aSmrg    int		    ret;
298823a0898aSmrg
298923a0898aSmrg    reply = fs_get_reply (conn, &err);
299023a0898aSmrg    if (!reply)
299123a0898aSmrg	return err;
299223a0898aSmrg
299323a0898aSmrg    ret = FSIO_READY;
299423a0898aSmrg    if (reply->type == FS_Error)
299523a0898aSmrg    {
299623a0898aSmrg	error = (fsError *) reply;
299723a0898aSmrg	if (error->major_opcode == FS_SetCatalogues)
299823a0898aSmrg	    ret = FSIO_ERROR;
299923a0898aSmrg    }
300023a0898aSmrg    _fs_done_read (conn, reply->length << 2);
300123a0898aSmrg    return ret;
300223a0898aSmrg}
300323a0898aSmrg
300423a0898aSmrgstatic void
300523a0898aSmrg_fs_close_server (FSFpePtr conn)
300623a0898aSmrg{
300723a0898aSmrg    _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
300823a0898aSmrg    if (conn->trans_conn)
300923a0898aSmrg    {
301023a0898aSmrg	_FontTransClose (conn->trans_conn);
301123a0898aSmrg	conn->trans_conn = 0;
301223a0898aSmrg	_fs_io_reinit (conn);
301323a0898aSmrg    }
301423a0898aSmrg    if (conn->fs_fd >= 0)
301523a0898aSmrg    {
301623a0898aSmrg	FD_CLR (conn->fs_fd, &_fs_fd_mask);
301723a0898aSmrg	conn->fs_fd = -1;
301823a0898aSmrg    }
301923a0898aSmrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
302023a0898aSmrg}
302123a0898aSmrg
302223a0898aSmrgstatic int
302323a0898aSmrg_fs_do_setup_connection (FSFpePtr conn)
302423a0898aSmrg{
302523a0898aSmrg    int	    ret;
302623a0898aSmrg
302723a0898aSmrg    do
302823a0898aSmrg    {
302923a0898aSmrg#ifdef DEBUG
303023a0898aSmrg	fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
303123a0898aSmrg#endif
303223a0898aSmrg	switch (conn->fs_conn_state) {
303323a0898aSmrg	case FS_CONN_UNCONNECTED:
303423a0898aSmrg	    ret = _fs_open_server (conn);
303523a0898aSmrg	    if (ret == FSIO_BLOCK)
303623a0898aSmrg		conn->fs_conn_state = FS_CONN_CONNECTING;
303723a0898aSmrg	    break;
303823a0898aSmrg	case FS_CONN_CONNECTING:
303923a0898aSmrg	    ret = _fs_check_connect (conn);
304023a0898aSmrg	    break;
304123a0898aSmrg	case FS_CONN_CONNECTED:
304223a0898aSmrg	    ret = _fs_send_conn_client_prefix (conn);
304323a0898aSmrg	    break;
304423a0898aSmrg	case FS_CONN_SENT_PREFIX:
304523a0898aSmrg	    ret = _fs_recv_conn_setup (conn);
304623a0898aSmrg	    break;
304723a0898aSmrg	case FS_CONN_RECV_INIT:
304823a0898aSmrg	    ret = _fs_send_init_packets (conn);
304923a0898aSmrg	    if (conn->has_catalogues)
305023a0898aSmrg		ret = _fs_send_cat_sync (conn);
305123a0898aSmrg	    break;
305223a0898aSmrg	case FS_CONN_SENT_CAT:
305323a0898aSmrg	    if (conn->has_catalogues)
305423a0898aSmrg		ret = _fs_recv_cat_sync (conn);
305523a0898aSmrg	    else
305623a0898aSmrg		ret = FSIO_READY;
305723a0898aSmrg	    break;
305823a0898aSmrg	default:
305923a0898aSmrg	    ret = FSIO_READY;
306023a0898aSmrg	    break;
306123a0898aSmrg	}
306223a0898aSmrg	switch (ret) {
306323a0898aSmrg	case FSIO_READY:
306423a0898aSmrg	    if (conn->fs_conn_state < FS_CONN_RUNNING)
306523a0898aSmrg		conn->fs_conn_state++;
306623a0898aSmrg	    break;
306723a0898aSmrg	case FSIO_BLOCK:
306823a0898aSmrg	    if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
306923a0898aSmrg		break;
307023a0898aSmrg	    ret = FSIO_ERROR;
307123a0898aSmrg	    /* fall through... */
307223a0898aSmrg	case FSIO_ERROR:
307323a0898aSmrg	    _fs_close_server (conn);
307423a0898aSmrg	    /*
307523a0898aSmrg	     * Try the next alternate
307623a0898aSmrg	     */
307723a0898aSmrg	    if (conn->alternate < conn->numAlts)
307823a0898aSmrg	    {
307923a0898aSmrg		conn->alternate++;
308023a0898aSmrg		ret = FSIO_READY;
308123a0898aSmrg	    }
308223a0898aSmrg	    else
308323a0898aSmrg		conn->alternate = 0;
308423a0898aSmrg	    break;
308523a0898aSmrg	}
308623a0898aSmrg    } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
308723a0898aSmrg    if (ret == FSIO_READY)
308823a0898aSmrg	conn->generation = ++generationCount;
308923a0898aSmrg    return ret;
309023a0898aSmrg}
309123a0898aSmrg
309223a0898aSmrgstatic int
309323a0898aSmrg_fs_wait_connect (FSFpePtr conn)
309423a0898aSmrg{
309523a0898aSmrg    int	    ret;
309623a0898aSmrg
309723a0898aSmrg    for (;;)
309823a0898aSmrg    {
309923a0898aSmrg	ret = _fs_do_setup_connection (conn);
310023a0898aSmrg	if (ret != FSIO_BLOCK)
310123a0898aSmrg	    break;
310223a0898aSmrg	if (conn->fs_conn_state <= FS_CONN_CONNECTING)
310323a0898aSmrg	    ret = _fs_poll_connect (conn->trans_conn, 1000);
310423a0898aSmrg	else
310523a0898aSmrg	    ret = _fs_wait_for_readable (conn, 1000);
310623a0898aSmrg	if (ret == FSIO_ERROR)
310723a0898aSmrg	    break;
310823a0898aSmrg    }
310923a0898aSmrg    return ret;
311023a0898aSmrg}
311123a0898aSmrg
311223a0898aSmrg/*
311323a0898aSmrg * Poll a connection in the process of reconnecting
311423a0898aSmrg */
311523a0898aSmrgstatic void
311623a0898aSmrg_fs_check_reconnect (FSFpePtr conn)
311723a0898aSmrg{
311823a0898aSmrg    int	    ret;
311923a0898aSmrg
312023a0898aSmrg    ret = _fs_do_setup_connection (conn);
312123a0898aSmrg    switch (ret) {
312223a0898aSmrg    case FSIO_READY:
312323a0898aSmrg	_fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
312423a0898aSmrg	_fs_restart_connection (conn);
312523a0898aSmrg	break;
312623a0898aSmrg    case FSIO_BLOCK:
312723a0898aSmrg	break;
312823a0898aSmrg    case FSIO_ERROR:
312923a0898aSmrg	conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
313023a0898aSmrg	break;
313123a0898aSmrg    }
313223a0898aSmrg}
313323a0898aSmrg
313423a0898aSmrg/*
313523a0898aSmrg * Start the reconnection process
313623a0898aSmrg */
313723a0898aSmrgstatic void
313823a0898aSmrg_fs_start_reconnect (FSFpePtr conn)
313923a0898aSmrg{
314023a0898aSmrg    if (conn->blockState & FS_RECONNECTING)
314123a0898aSmrg	return;
314223a0898aSmrg    conn->alternate = 0;
314323a0898aSmrg    _fs_mark_block (conn, FS_RECONNECTING);
314423a0898aSmrg    _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
314523a0898aSmrg    _fs_check_reconnect (conn);
314623a0898aSmrg}
314723a0898aSmrg
314823a0898aSmrg
314923a0898aSmrgstatic FSFpePtr
315023a0898aSmrg_fs_init_conn (char *servername)
315123a0898aSmrg{
315223a0898aSmrg    FSFpePtr	conn;
315323a0898aSmrg
31547f7f5e4eSmrg    conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
315523a0898aSmrg    if (!conn)
315623a0898aSmrg	return 0;
315723a0898aSmrg    if (!_fs_io_init (conn))
315823a0898aSmrg    {
31597f7f5e4eSmrg	free (conn);
316023a0898aSmrg	return 0;
316123a0898aSmrg    }
316223a0898aSmrg    conn->servername = (char *) (conn + 1);
316323a0898aSmrg    conn->fs_conn_state = FS_CONN_UNCONNECTED;
316423a0898aSmrg    conn->fs_fd = -1;
316523a0898aSmrg    strcpy (conn->servername, servername);
316623a0898aSmrg    return conn;
316723a0898aSmrg}
316823a0898aSmrg
316923a0898aSmrgstatic void
317023a0898aSmrg_fs_free_conn (FSFpePtr conn)
317123a0898aSmrg{
317223a0898aSmrg    _fs_close_server (conn);
317323a0898aSmrg    _fs_io_fini (conn);
317423a0898aSmrg    if (conn->alts)
31757f7f5e4eSmrg	free (conn->alts);
31767f7f5e4eSmrg    free (conn);
317723a0898aSmrg}
317823a0898aSmrg
317923a0898aSmrg/*
318023a0898aSmrg * called at server init time
318123a0898aSmrg */
318223a0898aSmrg
318323a0898aSmrgvoid
318423a0898aSmrgfs_register_fpe_functions(void)
318523a0898aSmrg{
318623a0898aSmrg    RegisterFPEFunctions(fs_name_check,
318723a0898aSmrg			 fs_init_fpe,
318823a0898aSmrg			 fs_free_fpe,
318923a0898aSmrg			 fs_reset_fpe,
319023a0898aSmrg			 fs_open_font,
319123a0898aSmrg			 fs_close_font,
319223a0898aSmrg			 fs_list_fonts,
319323a0898aSmrg			 fs_start_list_with_info,
319423a0898aSmrg			 fs_next_list_with_info,
319523a0898aSmrg			 fs_wakeup,
319623a0898aSmrg			 fs_client_died,
319723a0898aSmrg			 _fs_load_glyphs,
319823a0898aSmrg			 NULL,
319923a0898aSmrg			 NULL,
320023a0898aSmrg			 NULL);
320123a0898aSmrg}
3202