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