1 /* $TOG: fserve.c /main/49 1997/06/10 11:23:56 barstow $ */
2 /*
3 
4 Copyright (c) 1990  X Consortium
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26 
27 */
28 /* $XFree86: xc/lib/font/fc/fserve.c,v 3.4.2.2 1997/06/11 12:08:41 dawes Exp $ */
29 
30 /*
31  * Copyright 1990 Network Computing Devices
32  *
33  * Permission to use, copy, modify, distribute, and sell this software and
34  * its documentation for any purpose is hereby granted without fee, provided
35  * that the above copyright notice appear in all copies and that both that
36  * copyright notice and this permission notice appear in supporting
37  * documentation, and that the names of Network Computing Devices, or Digital
38  * not be used in advertising or publicity pertaining to distribution
39  * of the software without specific, written prior permission.
40  *
41  * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
42  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
43  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
44  * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
45  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
46  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
47  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
48  * THIS SOFTWARE.
49  *
50  * Author:  	Dave Lemke, Network Computing Devices, Inc
51  */
52 /*
53  * font server specific font access
54  */
55 
56 #ifdef WIN32
57 #define _WILLWINSOCK_
58 #endif
59 #include	<X11/X.h>
60 #include	<X11/Xos.h>
61 #include	"X11/Xpoll.h"
62 #include	"FS.h"
63 #include	"FSproto.h"
64 #include	"fontmisc.h"
65 #include	"fontstruct.h"
66 #include	"fservestr.h"
67 #include	<errno.h>
68 #if defined(X_NOT_STDC_ENV) && !defined(__EMX__)
69 extern int errno;
70 #define Time_t long
71 extern Time_t time ();
72 #else
73 #include	<time.h>
74 #define Time_t time_t
75 #endif
76 
77 #ifdef NCD
78 #include	<ncd/nvram.h>
79 #endif
80 
81 #ifndef NULL
82 #define NULL 0
83 #endif
84 
85 #ifndef MIN
86 #define MIN(a,b)    ((a)<(b)?(a):(b))
87 #endif
88 
89 #define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
90 			     (pci)->rightSideBearing || \
91 			     (pci)->ascent || \
92 			     (pci)->descent || \
93 			     (pci)->characterWidth)
94 
95 
96 extern FontPtr find_old_font();
97 
98 extern int  _fs_build_range();
99 
100 static int  fs_read_glyphs();
101 static int  fs_read_list();
102 static int  fs_read_list_info();
103 
104 static int  fs_font_type;
105 extern fd_set _fs_fd_mask;
106 
107 static void fs_block_handler();
108 static int  fs_wakeup();
109 
110 static FSFpePtr awaiting_reconnect;
111 
112 void        _fs_connection_died();
113 static int  _fs_restart_connection();
114 static void _fs_try_reconnect();
115 static int  fs_send_query_info();
116 static int  fs_send_query_extents();
117 static int  fs_send_query_bitmaps();
118 static int  fs_send_close_font();
119 static void fs_client_died();
120 static void _fs_client_access();
121 static void _fs_client_resolution();
122 
123 char _fs_glyph_undefined;
124 char _fs_glyph_requested;
125 char _fs_glyph_zero_length;
126 
127 /*
128  * Font server access
129  *
130  * the basic idea for the non-blocking access is to have the function
131  * called multiple times until the actual data is returned, instead
132  * of ClientBlocked.
133  *
134  * the first call to the function will cause the request to be sent to
135  * the font server, and a block record to be stored in the fpe's list
136  * of outstanding requests.  the FS block handler also sticks the
137  * proper set of fd's into the select mask.  when data is ready to be
138  * read in, the FS wakup handler will be hit.  this will read the
139  * data off the wire into the proper block record, and then signal the
140  * client that caused the block so that it can restart.  it will then
141  * call the access function again, which will realize that the data has
142  * arrived and return it.
143  */
144 
145 
146 /* XXX this should probably be a macro once its fully debugged */
147 /* ARGSUSED */
148 static void
_fs_add_req_log(conn,opcode)149 _fs_add_req_log(conn, opcode)
150     FSFpePtr    conn;
151     int         opcode;
152 {
153 
154 #ifdef DEBUG
155     conn->reqbuffer[conn->reqindex++] = opcode;
156     if (conn->reqindex == REQUEST_LOG_SIZE)
157 	conn->reqindex = 0;
158 #endif
159 
160     conn->current_seq++;
161 }
162 
163 static Bool
fs_name_check(name)164 fs_name_check(name)
165     char       *name;
166 {
167 #ifdef __EMX__
168     /* OS/2 uses D:/XFree86/.... as fontfile pathnames, so check that
169      * there is not only a protocol/ prefix, but also that the first chars
170      * are not a drive letter
171      */
172     if (name && isalpha(*name) && name[1] == ':')
173       return FALSE;
174 #endif
175     /* Just make sure there is a protocol/ prefix */
176     return (name && *name != '/' && strchr(name, '/'));
177 }
178 
179 static void
_fs_client_resolution(conn)180 _fs_client_resolution(conn)
181     FSFpePtr    conn;
182 {
183     fsSetResolutionReq srreq;
184     int         num_res;
185     FontResolutionPtr res;
186 
187     res = GetClientResolutions(&num_res);
188 
189     if (num_res) {
190 	srreq.reqType = FS_SetResolution;
191 	srreq.num_resolutions = num_res;
192 	srreq.length = (SIZEOF(fsSetResolutionReq) +
193 			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
194 
195 	_fs_add_req_log(conn, FS_SetResolution);
196 	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
197 	    (void)_fs_write_pad(conn, (char *) res,
198 				(num_res * SIZEOF(fsResolution)));
199     }
200 }
201 
202 /*
203  * sends the stuff that's meaningful to a newly opened or reset FS
204  */
205 static int
fs_send_init_packets(conn)206 fs_send_init_packets(conn)
207     FSFpePtr    conn;
208 {
209     fsSetResolutionReq srreq;
210     fsSetCataloguesReq screq;
211     fsListCataloguesReq lcreq;
212     fsListCataloguesReply lcreply;
213     int         num_cats,
214                 clen,
215                 len;
216     char       *client_cat = (char *) 0,
217                *cp,
218                *sp,
219                *end;
220     int         num_res;
221     FontResolutionPtr res;
222     int         err = Successful;
223 
224 #define	CATALOGUE_SEP	'+'
225 
226     res = GetClientResolutions(&num_res);
227     if (num_res) {
228 	srreq.reqType = FS_SetResolution;
229 	srreq.num_resolutions = num_res;
230 	srreq.length = (SIZEOF(fsSetResolutionReq) +
231 			(num_res * SIZEOF(fsResolution)) + 3) >> 2;
232 
233 	_fs_add_req_log(conn, FS_SetResolution);
234 	if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) == -1)
235 	{
236 	    err = BadFontPath;
237 	    goto fail;
238 	}
239 	if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) == -1)
240 	{
241 	    err = BadFontPath;
242 	    goto fail;
243 	}
244     }
245     sp = strrchr(conn->servername, '/');
246 
247     /* don't get tricked by a non-existant catalogue list */
248     if (sp == strchr(conn->servername, '/')) {
249 	/*
250 	 * try original name -- this might be an alternate with no catalogues
251 	 */
252 	sp = strrchr(conn->requestedname, '/');
253 	if (sp == strchr(conn->requestedname, '/'))
254 		sp = (char *) 0;
255     }
256     if (sp) {			/* turn cats into counted list */
257 	sp++;
258 	/* allocate more than enough room */
259 	cp = client_cat = (char *) xalloc(strlen(conn->servername));
260 	if (!cp) {
261 	    err = BadAlloc;
262 	    goto fail;
263 	}
264 	num_cats = 0;
265 	while (*sp) {
266 	    end = strchr(sp, CATALOGUE_SEP);
267 	    if (!end)
268 		end = sp + strlen(sp);
269 	    *cp++ = len = end - sp;
270 	    num_cats++;
271 	    memmove(cp, sp, len);
272 	    sp += len;
273 	    if (*sp == CATALOGUE_SEP)
274 		sp++;
275 	    cp += len;
276 	}
277 	clen = cp - client_cat;
278 	/* our list checked out, so send it */
279 	screq.reqType = FS_SetCatalogues;
280 	screq.num_catalogues = num_cats;
281 	screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
282 
283 	_fs_add_req_log(conn, FS_SetCatalogues);
284 	if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) == -1)
285 	{
286 	    err = BadFontPath;
287 	    goto fail;
288 	}
289 	if (_fs_write_pad(conn, (char *) client_cat, clen) == -1)
290 	{
291 	    err = BadFontPath;
292 	    goto fail;
293 	}
294 
295 	/*
296 	 * now sync up with the font server, to see if an error was generated
297 	 * by a bogus catalogue
298 	 */
299 	lcreq.reqType = FS_ListCatalogues;
300 	lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
301 	lcreq.maxNames = 0;
302 	lcreq.nbytes = 0;
303 	_fs_add_req_log(conn, FS_SetCatalogues);
304 	if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) == -1)
305 	{
306 	    err = BadFontPath;
307 	    goto fail;
308 	}
309 
310 	/*
311 	 * next bit will either by the ListCats reply, or an error followed by
312 	 * the reply
313 	 */
314 	if (_fs_read(conn, (char *) &lcreply, SIZEOF(fsGenericReply)) == -1) {
315 	    err = BadFontPath;
316 	    goto fail;
317 	}
318 	if (lcreply.type == FS_Error &&
319 		((fsError *) & lcreply)->major_opcode == FS_SetCatalogues) {
320 	    _fs_eat_rest_of_error(conn, (fsError *) & lcreply);
321 	    /* get ListCats response */
322 	    (void) _fs_read(conn, (char *) &lcreply,
323 			    SIZEOF(fsListCataloguesReply));
324 	    err = BadFontPath;
325 	    goto fail;
326 	}
327 	/* must be reply, swallow the rest of it */
328 	_fs_eat_rest_of_error(conn, (fsError *) & lcreply);
329     }
330 fail:
331     xfree(client_cat);
332     return err;
333 }
334 
335 /*
336  * close font server and remove any state associated with
337  * this connection - this includes any client records.
338  */
339 
340 static void
fs_close_conn(conn)341 fs_close_conn(conn)
342     FSFpePtr	conn;
343 {
344     FSClientPtr	client, nclient;
345 
346     /* XXX - hack.  The right fix is to remember that the font server
347        has gone away when we first discovered it. */
348     if (conn->trans_conn)
349         (void) _FontTransClose (conn->trans_conn);
350 
351     if (conn->fs_fd != -1)
352         FD_CLR(conn->fs_fd, &_fs_fd_mask);
353 
354     for (client = conn->clients; client; client = nclient)
355     {
356 	nclient = client->next;
357 	xfree (client);
358     }
359     conn->clients = NULL;
360 }
361 
362 /*
363  * the wakeup handlers have to be set when the FPE is open, and not
364  * removed until it is freed, in order to handle unexpected data, like
365  * events
366  */
367 /* ARGSUSED */
368 static int
fs_init_fpe(fpe)369 fs_init_fpe(fpe)
370     FontPathElementPtr fpe;
371 {
372     FSFpePtr    conn;
373     char       *name;
374     int         err;
375 
376     /* open font server */
377     /* create FS specific fpe info */
378     errno = 0;
379 
380     name = fpe->name;
381 
382     /* hack for old style names */
383     if (*name == ':')
384 	name++;			/* skip ':' */
385 
386     conn = _fs_open_server(name);
387     if (conn) {
388 	conn->requestedname = fpe->name; /* stash this for later init use */
389 	fpe->private = (pointer) conn;
390 	err = fs_send_init_packets(conn);
391 	if (err != Successful) {
392 	    fs_close_conn(conn);
393     	    xfree(conn->servername);
394     	    xfree(conn->alts);
395     	    xfree(conn);
396 	    return err;
397 	}
398 	if (init_fs_handlers(fpe, fs_block_handler) != Successful)
399 	    return AllocError;
400 	FD_SET(conn->fs_fd, &_fs_fd_mask);
401 	conn->attemptReconnect = TRUE;
402 
403 #ifdef NCD
404 	if (configData.ExtendedFontDiags)
405 	    printf("Connected to font server \"%s\"\n", name);
406 #endif
407 
408 	return err;
409     }
410 
411 #ifdef DEBUG
412     fprintf(stderr, "failed to connect to FS \"%s\"\n", name);
413 #endif
414 
415 #ifdef NCD
416     if (configData.ExtendedFontDiags)
417 	printf("Failed to connect to font server \"%s\"\n", name);
418 #endif
419 
420     return (errno == ENOMEM) ? AllocError : BadFontPath;
421 }
422 
423 static int
fs_reset_fpe(fpe)424 fs_reset_fpe(fpe)
425     FontPathElementPtr fpe;
426 {
427     (void) fs_send_init_packets((FSFpePtr) fpe->private);
428     return Successful;
429 }
430 
431 /*
432  * this shouldn't be called till all refs to the FPE are gone
433  */
434 
435 static int
fs_free_fpe(fpe)436 fs_free_fpe(fpe)
437     FontPathElementPtr fpe;
438 {
439     FSFpePtr    conn = (FSFpePtr) fpe->private;
440     FSFpePtr    recon,
441                *prev;
442     prev = &awaiting_reconnect;
443     while (*prev) {
444 	recon = *prev;
445 	if (conn == recon) {
446 	    *prev = recon->next_reconnect;
447 	    break;
448 	}
449 	prev = &recon->next_reconnect;
450     }
451 
452     fs_close_conn(conn);
453 
454     remove_fs_handlers(fpe, fs_block_handler,
455 		       !XFD_ANYSET(&_fs_fd_mask) && !awaiting_reconnect);
456 
457     xfree(conn->alts);
458     xfree(conn->servername);
459     xfree(conn);
460     fpe->private = (pointer) 0;
461 
462 #ifdef NCD
463     if (configData.ExtendedFontDiags)
464 	printf("Disconnected from font server \"%s\"\n", fpe->name);
465 #endif
466 
467     return Successful;
468 }
469 
470 static      FSBlockDataPtr
fs_new_block_rec(fpe,client,type)471 fs_new_block_rec(fpe, client, type)
472     FontPathElementPtr fpe;
473     pointer     client;
474     int         type;
475 {
476     FSBlockDataPtr blockrec,
477                 br;
478     FSFpePtr    fsfpe = (FSFpePtr) fpe->private;
479     int         size;
480 
481     blockrec = (FSBlockDataPtr) xalloc(sizeof(FSBlockDataRec));
482     if (!blockrec)
483 	return (FSBlockDataPtr) 0;
484     switch (type) {
485     case FS_OPEN_FONT:
486 	size = sizeof(FSBlockedFontRec);
487 	break;
488     case FS_LOAD_GLYPHS:
489 	size = sizeof(FSBlockedGlyphRec);
490 	break;
491     case FS_LIST_FONTS:
492 	size = sizeof(FSBlockedListRec);
493 	break;
494     case FS_LIST_WITH_INFO:
495 	size = sizeof(FSBlockedListInfoRec);
496 	break;
497     default:
498 	break;
499     }
500     blockrec->data = (pointer) xalloc(size);
501     if (!blockrec->data) {
502 	xfree(blockrec);
503 	return (FSBlockDataPtr) 0;
504     }
505     blockrec->client = client;
506     blockrec->sequence_number = fsfpe->current_seq;
507     blockrec->type = type;
508     blockrec->depending = 0;
509     blockrec->next = (FSBlockDataPtr) 0;
510 
511     /* stick it on the end of the list (since its expected last) */
512     br = (FSBlockDataPtr) fsfpe->blocked_requests;
513     if (!br) {
514 	fsfpe->blocked_requests = (pointer) blockrec;
515     } else {
516 	while (br->next)
517 	    br = br->next;
518 	br->next = blockrec;
519     }
520 
521     return blockrec;
522 }
523 
524 static void
_fs_remove_block_rec(conn,blockrec)525 _fs_remove_block_rec(conn, blockrec)
526     FSFpePtr    conn;
527     FSBlockDataPtr blockrec;
528 {
529     FSBlockDataPtr br,
530                 last;
531 
532     last = (FSBlockDataPtr) 0;
533     br = (FSBlockDataPtr) conn->blocked_requests;
534     while (br) {
535 	if (br == blockrec) {
536 	    if (last)
537 		last->next = br->next;
538 	    else
539 		conn->blocked_requests = (pointer) br->next;
540 	    if (br->type == FS_LOAD_GLYPHS)
541 	    {
542 		FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)br->data;
543 		if (bglyph->num_expected_ranges)
544 		    xfree(bglyph->expected_ranges);
545 	    }
546 	    xfree(br->data);
547 	    xfree(br);
548 	    return;
549 	}
550 	last = br;
551 	br = br->next;
552     }
553 }
554 
555 static void
signal_clients_depending(clients_depending)556 signal_clients_depending(clients_depending)
557 FSClientsDependingPtr *clients_depending;
558 {
559     FSClientsDependingPtr p = *clients_depending, p2;
560     *clients_depending = (FSClientsDependingPtr)0;
561 
562     while (p != (FSClientsDependingPtr)0)
563     {
564 	p2 = p;
565 	ClientSignal(p->client);
566 	p = p->next;
567 	xfree(p2);
568     }
569 }
570 
571 static int
add_clients_depending(clients_depending,client)572 add_clients_depending(clients_depending, client)
573 FSClientsDependingPtr *clients_depending;
574 pointer client;
575 {
576     while (*clients_depending != (FSClientsDependingPtr)0)
577     {
578 	if ((*clients_depending)->client == client) return Suspended;
579 	clients_depending = &(*clients_depending)->next;
580     }
581     *clients_depending = (FSClientsDependingPtr)xalloc(
582 			     sizeof(FSClientsDependingRec));
583     if (!*clients_depending)
584 	return BadAlloc;
585 
586     (*clients_depending)->client = client;
587     (*clients_depending)->next = 0;
588     return Suspended;
589 }
590 
591 static void
clean_aborted_blockrec(blockrec)592 clean_aborted_blockrec(blockrec)
593     FSBlockDataPtr blockrec;
594 {
595 
596     switch(blockrec->type)
597     {
598 	case FS_LOAD_GLYPHS:
599 	{
600 	    FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
601 	    FontPtr pfont = bglyph->pfont;
602 	    int num_expected_ranges = bglyph->num_expected_ranges;
603 	    fsRange *expected_ranges = bglyph->expected_ranges;
604 	    _fs_clean_aborted_loadglyphs(pfont,
605 				     num_expected_ranges,
606 				     expected_ranges);
607 	    signal_clients_depending(&bglyph->clients_depending);
608 	    break;
609 	}
610 	case FS_OPEN_FONT:
611 	{
612 	    FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
613 	    signal_clients_depending(&bfont->clients_depending);
614 	    break;
615 	}
616 	default:
617 	    break;
618     }
619 }
620 
621 static void
fs_abort_blockrec(conn,blockrec)622 fs_abort_blockrec(conn, blockrec)
623     FSFpePtr    conn;
624     FSBlockDataPtr blockrec;
625 {
626     clean_aborted_blockrec(blockrec);
627     _fs_remove_block_rec(conn, blockrec);
628 }
629 
630 
631 static void
fs_free_font(bfont)632 fs_free_font(bfont)
633     FSBlockedFontPtr bfont;
634 {
635     FontPtr     pfont;
636     FSFontDataRec *fsd;
637 
638     pfont = bfont->pfont;
639     fsd = (FSFontDataRec *) pfont->fpePrivate;
640 
641     /* xfree better be able to handle NULL */
642     (*pfont->unload_font)(pfont);
643     DeleteFontClientID(fsd->fontid);
644     xfree(fsd->name);
645     xfree(pfont->info.isStringProp);
646     xfree(pfont->info.props);
647 
648     xfree(pfont);
649     xfree(fsd);
650 
651     bfont->pfont = (FontPtr) 0;
652 }
653 
654 static void
_fs_cleanup_font(bfont)655 _fs_cleanup_font(bfont)
656     FSBlockedFontPtr bfont;
657 {
658     FSFontDataRec *fsd;
659 
660     if (bfont->pfont)
661     {
662     	fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
663 
664     	/* make sure the FS knows we choked on it */
665     	fs_send_close_font(fsd->fpe, bfont->fontid);
666 
667     	fs_free_font(bfont);
668     }
669     bfont->errcode = AllocError;
670 }
671 
672 
673 static int
fs_read_open_font(fpe,blockrec)674 fs_read_open_font(fpe, blockrec)
675     FontPathElementPtr fpe;
676     FSBlockDataPtr blockrec;
677 {
678     FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
679     FSFpePtr    conn = (FSFpePtr) fpe->private;
680     fsOpenBitmapFontReply rep;
681     FSBlockDataPtr blockOrig;
682     FSBlockedFontPtr origBfont;
683 
684     /* pull out the OpenFont reply */
685     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
686 
687     if (rep.type == FS_Error) {
688 	_fs_eat_rest_of_error(conn, (fsError *) & rep);
689 	return BadFontName;
690     } else {			/* get rest of reply */
691 	if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
692 	      SIZEOF(fsOpenBitmapFontReply) - SIZEOF(fsGenericReply)) == -1) {
693 	    /* If we're not reopening a font, we'll allocate the
694 	       structures again after connection is reestablished.  */
695 	    if (!(bfont->flags & FontReopen)) fs_free_font(bfont);
696 	    return StillWorking;
697 	}
698     }
699 
700     /* If we're not reopening a font and FS detected a duplicate font
701        open request, replace our reference to the new font with a
702        reference to an existing font (possibly one not finished
703        opening).  If this is a reopen, keep the new font reference...
704        it's got the metrics and extents we read when the font was opened
705        before.  This also gives us the freedom to easily close the font
706        if we we decide (in fs_read_query_info()) that we don't like what
707        we got. */
708 
709     if (rep.otherid && !(bfont->flags & FontReopen)) {
710 	(void) fs_send_close_font(fpe, bfont->fontid);
711 
712 	/* Find old font if we're completely done getting it from server. */
713 	fs_free_font(bfont);
714 	bfont->pfont = find_old_font(rep.otherid);
715 	bfont->fontid = rep.otherid;
716 	bfont->state = FS_DONE_REPLY;
717 	/*
718 	 * look for a blocked request to open the same font
719 	 */
720 	for (blockOrig = (FSBlockDataPtr) conn->blocked_requests;
721 		blockOrig;
722 		blockOrig = blockOrig->next) {
723 	    if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT) {
724 		origBfont = (FSBlockedFontPtr) blockOrig->data;
725 		if (origBfont->fontid == rep.otherid) {
726 		    blockrec->depending = blockOrig->depending;
727 		    blockOrig->depending = blockrec;
728 		    bfont->state = FS_DEPENDING;
729 		    bfont->pfont = origBfont->pfont;
730 		    break;
731 		}
732 	    }
733 	}
734 	if (bfont->pfont == NULL)
735 	{
736 	    /* XXX - something nasty happened */
737 	    return BadFontName;
738 	}
739 	return AccessDone;
740     }
741 
742     bfont->pfont->info.cachable = rep.cachable != 0;
743     bfont->state = FS_INFO_REPLY;
744     /* ask for the next stage */
745     (void) fs_send_query_info(fpe, blockrec);
746     return StillWorking;
747 }
748 
749 
750 static int
fs_read_query_info(fpe,blockrec)751 fs_read_query_info(fpe, blockrec)
752     FontPathElementPtr fpe;
753     FSBlockDataPtr blockrec;
754 {
755     FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
756     FSFpePtr    conn = (FSFpePtr) fpe->private;
757     fsQueryXInfoReply rep;
758     fsPropInfo  pi;
759     fsPropOffset *po;
760     pointer     pd;
761     unsigned long prop_len;
762     FSBlockedFontRec newbfont, *oldbfont;
763     FontRec newpfont, *oldpfont;
764     int err;
765 
766     /* If this is a reopen, accumulate the query info into a dummy
767        font and compare to our original data. */
768     if (bfont->flags & FontReopen)
769     {
770 	newbfont = *(oldbfont = bfont);
771 	bfont = &newbfont;
772 	newpfont = *(oldpfont = oldbfont->pfont);
773 	newpfont.info.isStringProp = NULL;
774 	newpfont.info.props = NULL;
775 	newbfont.pfont = &newpfont;
776 	err = StillWorking;
777     }
778 
779     /* pull out the QueryXInfo reply */
780     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
781     if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
782 		 SIZEOF(fsQueryXInfoReply) - SIZEOF(fsGenericReply)) == -1) {
783 	if (bfont->flags & FontReopen) goto bail;
784 	fs_free_font(bfont);
785 	return StillWorking;
786     }
787     /* move the data over */
788     fsUnpack_XFontInfoHeader(&rep, &bfont->pfont->info);
789     _fs_init_fontinfo(conn, &bfont->pfont->info);
790 
791     if (bfont->pfont->info.terminalFont)
792     {
793 	bfont->format =
794 	    (bfont->format & ~ (BitmapFormatImageRectMask)) |
795 	    BitmapFormatImageRectMax;
796     }
797 
798     if (_fs_read(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1) {
799 	if (bfont->flags & FontReopen) goto bail;
800 	fs_free_font(bfont);
801 	return StillWorking;
802     }
803     prop_len = pi.num_offsets * SIZEOF(fsPropOffset);
804     po = (fsPropOffset *) xalloc(prop_len);
805     pd = (pointer) xalloc(pi.data_len);
806     if (!po || !pd) {
807 	xfree(pd);
808 	xfree(po);
809 	/* clear the wire */
810 	(void) _fs_drain_bytes(conn, prop_len + pi.data_len);
811 	/* clean up the font */
812 	if (bfont->flags & FontReopen) { err = AllocError ; goto bail; }
813 	(void) _fs_cleanup_font(bfont);
814 	return AllocError;
815     }
816     if (_fs_read_pad(conn, (char *) po, prop_len) == -1 ||
817 	    _fs_read_pad(conn, (char *) pd, pi.data_len) == -1) {
818 	xfree(pd);
819 	xfree(po);
820 	if (bfont->flags & FontReopen) goto bail;
821 	fs_free_font(bfont);
822 	return StillWorking;
823     }
824     if (_fs_convert_props(&pi, po, pd, &bfont->pfont->info) == -1)
825     {
826     	xfree(po);
827     	xfree(pd);
828 	if (bfont->flags & FontReopen) { err = AllocError ; goto bail; }
829 	(void) _fs_cleanup_font(bfont);
830 	return AllocError;
831     }
832     xfree(po);
833     xfree(pd);
834 
835     if (bfont->flags & FontReopen)
836     {
837 	int i;
838 
839 	err = BadFontName;
840 
841 	/* We're reopening a font that we lost because of a downed
842 	   connection.  In the interest of avoiding corruption from
843 	   opening a different font than the old one (we already have
844 	   its metrics, extents, and probably some of its glyphs),
845 	   verify that the metrics and properties all match.  */
846 
847 	if (newpfont.info.firstCol != oldpfont->info.firstCol ||
848 	    newpfont.info.lastCol != oldpfont->info.lastCol ||
849 	    newpfont.info.firstRow != oldpfont->info.firstRow ||
850 	    newpfont.info.lastRow != oldpfont->info.lastRow ||
851 	    newpfont.info.defaultCh != oldpfont->info.defaultCh ||
852 	    newpfont.info.noOverlap != oldpfont->info.noOverlap ||
853 	    newpfont.info.terminalFont != oldpfont->info.terminalFont ||
854 	    newpfont.info.constantMetrics != oldpfont->info.constantMetrics ||
855 	    newpfont.info.constantWidth != oldpfont->info.constantWidth ||
856 	    newpfont.info.inkInside != oldpfont->info.inkInside ||
857 	    newpfont.info.inkMetrics != oldpfont->info.inkMetrics ||
858 	    newpfont.info.allExist != oldpfont->info.allExist ||
859 	    newpfont.info.drawDirection != oldpfont->info.drawDirection ||
860 	    newpfont.info.cachable != oldpfont->info.cachable ||
861 	    newpfont.info.anamorphic != oldpfont->info.anamorphic ||
862 	    newpfont.info.maxOverlap != oldpfont->info.maxOverlap ||
863 	    newpfont.info.fontAscent != oldpfont->info.fontAscent ||
864 	    newpfont.info.fontDescent != oldpfont->info.fontDescent ||
865 	    newpfont.info.nprops != oldpfont->info.nprops)
866 	    goto bail;
867 
868 #define MATCH(xci1, xci2) \
869 	(((xci1).leftSideBearing == (xci2).leftSideBearing) && \
870 	 ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
871 	 ((xci1).characterWidth == (xci2).characterWidth) && \
872 	 ((xci1).ascent == (xci2).ascent) && \
873 	 ((xci1).descent == (xci2).descent) && \
874 	 ((xci1).attributes == (xci2).attributes))
875 
876 	if (!MATCH(newpfont.info.maxbounds, oldpfont->info.maxbounds) ||
877 	    !MATCH(newpfont.info.minbounds, oldpfont->info.minbounds) ||
878 	    !MATCH(newpfont.info.ink_maxbounds, oldpfont->info.ink_maxbounds) ||
879 	    !MATCH(newpfont.info.ink_minbounds, oldpfont->info.ink_minbounds))
880 	    goto bail;
881 
882 #undef MATCH
883 
884 	for (i = 0; i < newpfont.info.nprops; i++)
885 	    if (newpfont.info.isStringProp[i] !=
886 		    oldpfont->info.isStringProp[i] ||
887 		newpfont.info.props[i].name !=
888 		    oldpfont->info.props[i].name ||
889 		newpfont.info.props[i].value !=
890 		    oldpfont->info.props[i].value)
891 		goto bail;
892 
893 	err = Successful;
894     bail:
895 	if (err != Successful && err != StillWorking)
896 	{
897 	    /* Failure.  Close the font. */
898     	    fs_send_close_font(((FSFontDataPtr)oldpfont->fpePrivate)->fpe,
899 			       bfont->fontid);
900 	    ((FSFontDataPtr)oldpfont->fpePrivate)->generation  = -1;
901 	}
902 	xfree(newpfont.info.isStringProp);
903 	xfree(newpfont.info.props);
904 
905 	if (err == Successful) oldbfont->state = FS_DONE_REPLY;
906 	return err;
907     }
908 
909     if (glyphCachingMode == CACHING_OFF ||
910 	glyphCachingMode == CACHE_16_BIT_GLYPHS && !bfont->pfont->info.lastRow)
911 	bfont->flags |= FontLoadAll;
912 
913     bfont->state = FS_EXTENT_REPLY;
914 
915     fs_send_query_extents(fpe, blockrec);
916     return StillWorking;
917 }
918 
919 static int
fs_read_extent_info(fpe,blockrec)920 fs_read_extent_info(fpe, blockrec)
921     FontPathElementPtr fpe;
922     FSBlockDataPtr blockrec;
923 {
924     FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
925     FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
926     FSFpePtr    conn = (FSFpePtr) fpe->private;
927     fsQueryXExtents16Reply rep;
928     int         i;
929     int		numInfos;
930     Bool	haveInk = FALSE; /* need separate ink metrics? */
931     CharInfoPtr ci,
932                 pCI;
933     FSFontPtr   fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
934     fsXCharInfo *fsci;
935     fsXCharInfo fscilocal;
936     pointer fscip;
937 
938     /* read the QueryXExtents reply */
939     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
940     if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
941 	      SIZEOF(fsQueryXExtents16Reply) - SIZEOF(fsGenericReply)) == -1) {
942 	fs_free_font(bfont);
943 	return StillWorking;
944     }
945     /* move the data over */
946     /* need separate inkMetrics for fixed font server protocol version */
947     numInfos =  rep.num_extents;
948     if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
949     {
950 	numInfos *= 2;
951 	haveInk = TRUE;
952     }
953     ci = pCI = (CharInfoPtr) xalloc(sizeof(CharInfoRec) * numInfos);
954 /* XXX this could be done with an ALLOCATE_LOCAL */
955     fsci = (fsXCharInfo *) xalloc(SIZEOF(fsXCharInfo) * rep.num_extents);
956     if (!pCI || !fsci) {
957 	xfree(pCI);
958 	xfree(fsci);
959 	/* clear the unusable data */
960 	_fs_drain_bytes(conn, SIZEOF(fsXCharInfo) * rep.num_extents);
961 	_fs_cleanup_font(bfont);
962 	return AllocError;
963     }
964     fsfont->encoding = pCI;
965     if (haveInk)
966 	fsfont->inkMetrics = pCI + rep.num_extents;
967     else
968         fsfont->inkMetrics = pCI;
969 
970     if (_fs_read_pad(conn, (char *) fsci,
971 		     SIZEOF(fsXCharInfo) * rep.num_extents) == -1) {
972 	fs_free_font(bfont);
973 	xfree(fsci);
974 	return StillWorking;
975     }
976     fsd->glyphs_to_get = 0;
977     fscip = (pointer) fsci;
978     ci = fsfont->inkMetrics;
979     for (i = 0; i < rep.num_extents; i++) {
980 	memcpy(&fscilocal, fscip, SIZEOF(fsXCharInfo)); /* align it */
981 	_fs_convert_char_info(&fscilocal, &ci->metrics);
982 	fscip += SIZEOF(fsXCharInfo);
983 	/* Initialize the bits field for later glyph-caching use */
984 	if (NONZEROMETRICS(&ci->metrics))
985 	{
986 	    if (!haveInk &&
987 		(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
988 		 ci->metrics.ascent == -ci->metrics.descent))
989 		pCI[i].bits = &_fs_glyph_zero_length;
990 	    else
991 	    {
992 		pCI[i].bits = &_fs_glyph_undefined;
993 		fsd->glyphs_to_get++;
994 	    }
995 	}
996 	else
997 	    pCI[i].bits = (char *)0;
998 	ci++;
999     }
1000 
1001     xfree(fsci);
1002 
1003     /* build bitmap metrics, ImageRectMax style */
1004     if (haveInk)
1005     {
1006 	FontInfoRec *fi = &bfont->pfont->info;
1007 	CharInfoPtr ii;
1008 
1009 	ci = fsfont->encoding;
1010 	ii = fsfont->inkMetrics;
1011 	for (i = 0; i < rep.num_extents; i++, ci++, ii++)
1012 	{
1013 	    if (NONZEROMETRICS(&ii->metrics))
1014 	    {
1015 		ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
1016 		ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
1017 		ci->metrics.ascent = FONT_MAX_ASCENT(fi);
1018 		ci->metrics.descent = FONT_MAX_DESCENT(fi);
1019 		ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
1020 		ci->metrics.attributes = ii->metrics.attributes;
1021 	    }
1022 	    else
1023 	    {
1024 		ci->metrics = ii->metrics;
1025 	    }
1026 	}
1027     }
1028     {
1029 	unsigned int r, c, numCols, firstCol;
1030 
1031 	firstCol = bfont->pfont->info.firstCol;
1032 	numCols = bfont->pfont->info.lastCol - firstCol + 1;
1033 	c = bfont->pfont->info.defaultCh;
1034 	fsfont->pDefault = 0;
1035 	if (bfont->pfont->info.lastRow)
1036 	{
1037 	    r = c >> 8;
1038 	    r -= bfont->pfont->info.firstRow;
1039 	    c &= 0xff;
1040 	    c -= firstCol;
1041 	    if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
1042 		c < numCols)
1043 		fsfont->pDefault = &pCI[r * numCols + c];
1044 	}
1045 	else
1046 	{
1047 	    c -= firstCol;
1048 	    if (c < numCols)
1049 		fsfont->pDefault = &pCI[c];
1050 	}
1051     }
1052     bfont->state = FS_GLYPHS_REPLY;
1053 
1054     if (bfont->flags & FontLoadBitmaps) {
1055 	fs_send_query_bitmaps(fpe, blockrec);
1056 	return StillWorking;
1057     }
1058     return Successful;
1059 }
1060 
1061 /*
1062  * XXX should probably continue to read here if we can, but must be sure
1063  * it's our packet waiting, rather than another interspersed
1064  */
1065 static int
fs_do_open_font(fpe,blockrec,readheader)1066 fs_do_open_font(fpe, blockrec, readheader)
1067     FontPathElementPtr fpe;
1068     FSBlockDataPtr blockrec;
1069     Bool        readheader;
1070 {
1071     FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
1072     FSFpePtr    conn = (FSFpePtr) fpe->private;
1073     int         err;
1074 
1075     switch (bfont->state) {
1076     case FS_OPEN_REPLY:
1077 	if (readheader) {
1078 	    /* get the next header */
1079 	    if (_fs_read(conn, (char *) &blockrec->header,
1080 			 SIZEOF(fsGenericReply)) == -1) {
1081 		fs_free_font(bfont);
1082 		err = StillWorking;
1083 		break;
1084 	    }
1085 	}
1086 	bfont->errcode = fs_read_open_font(fpe, blockrec);
1087 	if (bfont->errcode != StillWorking) {	/* already loaded, or error */
1088 	    /* if font's already loaded, massage error code */
1089 	    switch (bfont->state) {
1090 	    case FS_DONE_REPLY:
1091 		bfont->errcode = Successful;
1092 		break;
1093 	    case FS_DEPENDING:
1094 		bfont->errcode = StillWorking;
1095 		break;
1096 	    }
1097 	    err = bfont->errcode;
1098 	    break;
1099 	}
1100 	/* if more data to read or Sync, fall thru, else return */
1101 	if (!(bfont->flags & FontOpenSync)) {
1102 	    err = bfont->errcode;
1103 	    break;
1104 	} else {
1105 	    if (_fs_read(conn, (char *) &blockrec->header,
1106 			 SIZEOF(fsGenericReply)) == -1) {
1107 		fs_free_font(bfont);
1108 		err = StillWorking;
1109 		break;
1110 	    }
1111 	}
1112 	/* fall through */
1113     case FS_INFO_REPLY:
1114 	bfont->errcode = fs_read_query_info(fpe, blockrec);
1115 	if (bfont->errcode != StillWorking) {
1116 	    err = bfont->errcode;
1117 	    break;
1118 	}
1119 	if (!(bfont->flags & FontOpenSync)) {
1120 	    err = bfont->errcode;
1121 	    break;
1122 	    /* if more data to read, fall thru, else return */
1123 	} else {
1124 	    if (_fs_read(conn, (char *) &blockrec->header,
1125 			 SIZEOF(fsGenericReply))) {
1126 		fs_free_font(bfont);
1127 		err = StillWorking;
1128 		break;
1129 	    }
1130 	}
1131 	/* fall through */
1132     case FS_EXTENT_REPLY:
1133 	bfont->errcode = fs_read_extent_info(fpe, blockrec);
1134 	if (bfont->errcode != StillWorking) {
1135 	    err = bfont->errcode;
1136 	    break;
1137 	}
1138 	if (!(bfont->flags & FontOpenSync)) {
1139 	    err = bfont->errcode;
1140 	    break;
1141 	} else if (bfont->flags & FontLoadBitmaps) {
1142 	    if (_fs_read(conn, (char *) &blockrec->header,
1143 			 SIZEOF(fsGenericReply))) {
1144 		fs_free_font(bfont);
1145 		err = StillWorking;
1146 		break;
1147 	    }
1148 	}
1149 	/* fall through */
1150     case FS_GLYPHS_REPLY:
1151 	if (bfont->flags & FontLoadBitmaps) {
1152 	    bfont->errcode = fs_read_glyphs(fpe, blockrec);
1153 	}
1154 	err = bfont->errcode;
1155 	break;
1156     case FS_DEPENDING:		/* can't happen */
1157 	err = bfont->errcode;
1158     default:
1159 	err = bfont->errcode;
1160 	break;
1161     }
1162     if (err != StillWorking) {
1163 	bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1164 	while (blockrec = blockrec->depending) {
1165 	    bfont = (FSBlockedFontPtr) blockrec->data;
1166 	    bfont->errcode = err;
1167 	    bfont->state = FS_DONE_REPLY;	/* for _fs_load_glyphs() */
1168 	}
1169     }
1170     return err;
1171 }
1172 
1173 /* ARGSUSED */
1174 static void
fs_block_handler(data,wt,LastSelectMask)1175 fs_block_handler(data, wt, LastSelectMask)
1176     pointer     data;
1177     struct timeval **wt;
1178     fd_set*      LastSelectMask;
1179 {
1180     static struct timeval recon_timeout;
1181     Time_t      now,
1182                 soonest;
1183     FSFpePtr    recon;
1184 
1185     XFD_ORSET(LastSelectMask, LastSelectMask, &_fs_fd_mask);
1186     if (recon = awaiting_reconnect) {
1187 	now = time((Time_t *) 0);
1188 	soonest = recon->time_to_try;
1189 	while (recon = recon->next_reconnect) {
1190 	    if (recon->time_to_try < soonest)
1191 		soonest = recon->time_to_try;
1192 	}
1193 	if (soonest < now)
1194 	    soonest = now;
1195 	soonest = soonest - now;
1196 	recon_timeout.tv_sec = soonest;
1197 	recon_timeout.tv_usec = 0;
1198 	if (*wt == (struct timeval *) 0) {
1199 	    *wt = &recon_timeout;
1200 	} else if ((*wt)->tv_sec > soonest) {
1201 	    **wt = recon_timeout;
1202 	}
1203     }
1204 }
1205 
1206 static void
fs_handle_unexpected(conn,rep)1207 fs_handle_unexpected(conn, rep)
1208     FSFpePtr    conn;
1209     fsGenericReply *rep;
1210 {
1211     if (rep->type == FS_Event && rep->data1 == KeepAlive) {
1212 	fsNoopReq   req;
1213 
1214 	/* ping it back */
1215 	req.reqType = FS_Noop;
1216 	req.length = SIZEOF(fsNoopReq) >> 2;
1217 	_fs_add_req_log(conn, FS_Noop);
1218 	_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
1219     }
1220     /* this should suck up unexpected replies and events */
1221     _fs_eat_rest_of_error(conn, (fsError *) rep);
1222 }
1223 
1224 static int
fs_wakeup(fpe,LastSelectMask)1225 fs_wakeup(fpe, LastSelectMask)
1226     FontPathElementPtr fpe;
1227     fd_set* LastSelectMask;
1228 {
1229     FSBlockDataPtr blockrec,
1230                 br;
1231     FSFpePtr    conn = (FSFpePtr) fpe->private;
1232     int         err;
1233     fsGenericReply rep;
1234 
1235     if (awaiting_reconnect) {
1236 	_fs_try_reconnect();
1237     }
1238 
1239     /* see if there's any data to be read */
1240 
1241     /*
1242      * Don't continue if the fd is -1 (which will be true when the
1243      * font server terminates
1244      */
1245     if (conn->fs_fd == -1)
1246 	return FALSE;
1247 
1248     if (FD_ISSET(conn->fs_fd, LastSelectMask)) {
1249 
1250 #if defined(NOTDEF) || defined(__EMX__)		/* bogus - doesn't deal with EOF very well,
1251 				 * now does it ... */
1252 	/*
1253 	 * make sure it isn't spurious - mouse events seem to trigger extra
1254 	 * problems. Under OS/2, this is especially true ...
1255 	 */
1256 	if (_fs_data_ready(conn) <= 0) {
1257 	    return FALSE;
1258 	}
1259 #endif
1260 
1261 	/* get the header */
1262 	if (_fs_read(conn, (char *) &rep, SIZEOF(fsGenericReply)) == -1)
1263 	    return FALSE;
1264 
1265 	/* find the matching block record */
1266 
1267 	for (br = (FSBlockDataPtr) conn->blocked_requests; br; br = br->next) {
1268 	    if ((CARD16)(br->sequence_number & 0xffff) ==
1269 		(CARD16)(rep.sequenceNumber - 1))
1270 		break;
1271 	}
1272 	if (!br) {
1273 	    fs_handle_unexpected(conn, &rep);
1274 	    return FALSE;
1275 	}
1276 	blockrec = br;
1277 
1278 	memcpy(&blockrec->header, &rep, SIZEOF(fsGenericReply));
1279 
1280 	/* go read it, and if we're done, wake up the appropriate client */
1281 	switch (blockrec->type) {
1282 	case FS_OPEN_FONT:
1283 	    err = fs_do_open_font(fpe, blockrec, FALSE);
1284 	    break;
1285 	case FS_LOAD_GLYPHS:
1286 	    err = fs_read_glyphs(fpe, blockrec);
1287 	    break;
1288 	case FS_LIST_FONTS:
1289 	    err = fs_read_list(fpe, blockrec);
1290 	    break;
1291 	case FS_LIST_WITH_INFO:
1292 	    err = fs_read_list_info(fpe, blockrec);
1293 	    break;
1294 	default:
1295 	    break;
1296 	}
1297 
1298 	if (err != StillWorking) {
1299 	    while (blockrec) {
1300 		ClientSignal(blockrec->client);
1301 		blockrec = blockrec->depending;
1302 	    }
1303 	}
1304 	/*
1305 	 * Xx we could loop here and eat any additional replies, but it should
1306 	 * feel more responsive for other clients if we come back later
1307 	 */
1308     } else if (awaiting_reconnect) {
1309 	_fs_try_reconnect();
1310     }
1311     return FALSE;
1312 }
1313 
1314 /*
1315  * Reconnection code
1316  */
1317 
1318 void
_fs_connection_died(conn)1319 _fs_connection_died(conn)
1320     FSFpePtr    conn;
1321 {
1322     if (!conn->attemptReconnect)
1323 	return;
1324     conn->attemptReconnect = FALSE;
1325     fs_close_conn(conn);
1326     conn->time_to_try = time((Time_t *) 0) + FS_RECONNECT_WAIT;
1327     conn->reconnect_delay = FS_RECONNECT_WAIT;
1328     conn->fs_fd = -1;
1329     conn->trans_conn = NULL;
1330     conn->next_reconnect = awaiting_reconnect;
1331     awaiting_reconnect = conn;
1332 }
1333 
1334 static int
_fs_restart_connection(conn)1335 _fs_restart_connection(conn)
1336     FSFpePtr    conn;
1337 {
1338     FSBlockDataPtr block;
1339 
1340     conn->current_seq = 0;
1341     FD_SET(conn->fs_fd, &_fs_fd_mask);
1342     if (!fs_send_init_packets(conn))
1343 	return FALSE;
1344     while (block = (FSBlockDataPtr) conn->blocked_requests) {
1345 	ClientSignal(block->client);
1346 	fs_abort_blockrec(conn, block);
1347     }
1348     return TRUE;
1349 }
1350 
1351 static void
_fs_try_reconnect()1352 _fs_try_reconnect()
1353 {
1354     FSFpePtr    conn,
1355                *prev;
1356     Time_t      now;
1357 
1358     prev = &awaiting_reconnect;
1359     now = time((Time_t *) 0);
1360     while (conn = *prev) {
1361 	if (now - conn->time_to_try > 0) {
1362 	    if (_fs_reopen_server(conn) && _fs_restart_connection(conn)) {
1363 		conn->attemptReconnect = TRUE;
1364 		*prev = conn->next_reconnect;
1365 		if (prev == &awaiting_reconnect) continue;
1366 	    } else {
1367 		if (conn->reconnect_delay < FS_MAX_RECONNECT_WAIT)
1368 		    conn->reconnect_delay *= 2;
1369 		now = time((Time_t *) 0);
1370 		conn->time_to_try = now + conn->reconnect_delay;
1371 	    }
1372 	}
1373 	prev = &conn->next_reconnect;
1374     }
1375 }
1376 
1377 /*
1378  * sends the actual request out
1379  */
1380 /* ARGSUSED */
1381 static int
fs_send_open_font(client,fpe,flags,name,namelen,format,fmask,id,ppfont)1382 fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont)
1383     pointer     client;
1384     FontPathElementPtr fpe;
1385     Mask        flags;
1386     char       *name;
1387     int         namelen;
1388     fsBitmapFormat format;
1389     fsBitmapFormatMask fmask;
1390     XID         id;
1391     FontPtr    *ppfont;
1392 {
1393     FontPtr     newfont;
1394     FSBlockDataPtr blockrec = NULL;
1395     FSBlockedFontPtr blockedfont;
1396     FSFontDataPtr fsd;
1397     FSFontPtr   fsfont;
1398     FSFpePtr    conn;
1399     fsOpenBitmapFontReq openreq;
1400     int         err = Suspended;
1401     XID         newid;
1402     unsigned char buf[1024];
1403     char       *fontname;
1404 
1405     if (flags & FontReopen)
1406     {
1407 	Atom nameatom, fn = None;
1408 	int i;
1409 
1410 	newfont = *ppfont;
1411 	fsd = (FSFontDataPtr)newfont->fpePrivate;
1412 	fsfont = (FSFontPtr)newfont->fontPrivate;
1413 	fpe = newfont->fpe;
1414 	format = fsd->format;
1415 	fmask = fsd->fmask;
1416 	newid = fsd->fontid;
1417 	/* This is an attempt to reopen a font.  Did the font have a
1418 	   NAME property? */
1419 	if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
1420 	{
1421 	    for (i = 0; i < newfont->info.nprops; i++)
1422 		if (newfont->info.props[i].name == nameatom &&
1423 		    newfont->info.isStringProp[i])
1424 		{
1425 		    fn = newfont->info.props[i].value;
1426 		    break;
1427 		}
1428 	}
1429 	if (fn == None || !(name = NameForAtom(fn)))
1430 	{
1431 	    name = fsd->name;
1432 	    namelen = fsd->namelen;
1433 	}
1434 	else
1435 	    namelen = strlen(name);
1436     }
1437 
1438     conn = (FSFpePtr) fpe->private;
1439     if (namelen > sizeof (buf) - 1)
1440 	return BadFontName;
1441     _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
1442     _fs_client_resolution(conn);
1443 
1444 
1445     if (!(flags & FontReopen))
1446     {
1447 
1448 	newid = GetNewFontClientID();
1449 
1450 	/* make the font */
1451 	newfont = (FontPtr) xalloc(sizeof(FontRec));
1452 
1453 	/* and the FS data */
1454 	fsd = (FSFontDataPtr) xalloc(sizeof(FSFontDataRec));
1455 
1456 	fsfont = (FSFontPtr) xalloc(sizeof(FSFontRec));
1457 
1458 	fontname = (char *)xalloc(namelen);
1459 
1460 	if (!newfont || !fsd || !fsfont || !fontname) {
1461 lowmem:
1462 	    if (!(flags & FontReopen))
1463 	    {
1464 		xfree((char *) newfont);
1465 		xfree((char *) fsd);
1466 		xfree((char *) fsfont);
1467 		xfree((char *) fontname);
1468 	    }
1469 	    if (blockrec) fs_abort_blockrec(conn, blockrec);
1470 	    return AllocError;
1471 	}
1472 	bzero((char *) newfont, sizeof(FontRec));
1473 	bzero((char *) fsfont, sizeof(FSFontRec));
1474 	bzero((char *) fsd, sizeof(FSFontDataRec));
1475     }
1476 
1477     /* make a new block record, and add it to the end of the list */
1478     blockrec = fs_new_block_rec(fpe, client, FS_OPEN_FONT);
1479     if (!blockrec) {
1480 	goto lowmem;
1481     }
1482 
1483     if (!(flags & FontReopen))
1484     {
1485 	int bit, byte, scan, glyph;
1486 
1487 	newfont->refcnt = 0;
1488 	newfont->maxPrivate = -1;
1489 	newfont->devPrivates = (pointer *) 0;
1490 	newfont->format = format;
1491 
1492 	/* These font components will be needed in packGlyphs */
1493 	CheckFSFormat(format, BitmapFormatMaskBit |
1494 			      BitmapFormatMaskByte |
1495 			      BitmapFormatMaskScanLineUnit |
1496 			      BitmapFormatMaskScanLinePad,
1497 		      &bit,
1498 		      &byte,
1499 		      &scan,
1500 		      &glyph,
1501 		      NULL);
1502 	newfont->bit = bit;
1503 	newfont->byte = byte;
1504 	newfont->scan = scan;
1505 	newfont->glyph = glyph;
1506 
1507 	newfont->fpe = fpe;
1508 	newfont->fpePrivate = (pointer) fsd;
1509 	newfont->fontPrivate = (pointer) fsfont;
1510 	_fs_init_font(newfont);
1511 
1512 	fsd->fpe = fpe;
1513 	fsd->name = fontname;
1514 	fsd->namelen = namelen;
1515 	memcpy(fontname, name, namelen);
1516 	fsd->format = format;
1517 	fsd->fmask = fmask;
1518     }
1519     fsd->fontid = newid;
1520     fsd->generation = conn->generation;
1521 
1522     blockedfont = (FSBlockedFontPtr) blockrec->data;
1523     blockedfont->fontid = newid;
1524     blockedfont->pfont = newfont;
1525     blockedfont->state = FS_OPEN_REPLY;
1526     blockedfont->flags = flags;
1527     blockedfont->format = format;
1528     blockedfont->clients_depending = (FSClientsDependingPtr)0;
1529 
1530     /* save the ID */
1531     if (!StoreFontClientFont(blockedfont->pfont, blockedfont->fontid)) {
1532 	goto lowmem;
1533     }
1534     /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
1535     buf[0] = (unsigned char) namelen;
1536     memcpy(&buf[1], name, namelen);
1537     namelen++;
1538     openreq.reqType = FS_OpenBitmapFont;
1539     openreq.fid = newid;
1540     openreq.format_hint = format;
1541     openreq.format_mask = fmask;
1542     openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 3) >> 2;
1543 
1544     _fs_add_req_log(conn, FS_OpenBitmapFont);
1545     _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
1546     _fs_write_pad(conn, (char *) buf, namelen);
1547 
1548 #ifdef NCD
1549     if (configData.ExtendedFontDiags) {
1550 	memcpy(buf, name, MIN(256, namelen));
1551 	buf[MIN(256, namelen)] = '\0';
1552 	printf("Requesting font \"%s\" from font server \"%s\"\n",
1553 	       buf, fpe->name);
1554     }
1555 #endif
1556 
1557     if (flags & FontOpenSync) {
1558 	err = fs_do_open_font(fpe, blockrec, TRUE);
1559 	if (blockedfont->errcode == Successful) {
1560 	    *ppfont = blockedfont->pfont;
1561 	} else {
1562 	    _fs_cleanup_font(blockedfont);
1563 	}
1564 	_fs_remove_block_rec(conn, blockrec);
1565     }
1566     return err;
1567 }
1568 
1569 static int
fs_send_query_info(fpe,blockrec)1570 fs_send_query_info(fpe, blockrec)
1571     FontPathElementPtr fpe;
1572     FSBlockDataPtr blockrec;
1573 {
1574     FSBlockedFontPtr bfont;
1575     FSFpePtr    conn = (FSFpePtr) fpe->private;
1576     fsQueryXInfoReq inforeq;
1577 
1578     bfont = (FSBlockedFontPtr) blockrec->data;
1579 
1580     inforeq.reqType = FS_QueryXInfo;
1581     inforeq.id = bfont->fontid;
1582     inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
1583 
1584     blockrec->sequence_number = conn->current_seq;
1585     _fs_add_req_log(conn, FS_QueryXInfo);
1586     _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
1587 
1588     return Successful;
1589 }
1590 
1591 static int
fs_send_query_extents(fpe,blockrec)1592 fs_send_query_extents(fpe, blockrec)
1593     FontPathElementPtr fpe;
1594     FSBlockDataPtr blockrec;
1595 {
1596     FSBlockedFontPtr bfont;
1597     FSFpePtr    conn = (FSFpePtr) fpe->private;
1598     fsQueryXExtents16Req extreq;
1599 
1600     bfont = (FSBlockedFontPtr) blockrec->data;
1601 
1602     extreq.reqType = FS_QueryXExtents16;
1603     extreq.range = fsTrue;
1604     extreq.fid = bfont->fontid;
1605     extreq.num_ranges = 0;
1606     extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
1607 
1608     blockrec->sequence_number = conn->current_seq;
1609     _fs_add_req_log(conn, FS_QueryXExtents16);
1610     _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
1611 
1612     return Successful;
1613 }
1614 
1615 static int
fs_send_query_bitmaps(fpe,blockrec)1616 fs_send_query_bitmaps(fpe, blockrec)
1617     FontPathElementPtr fpe;
1618     FSBlockDataPtr blockrec;
1619 {
1620     FSBlockedFontPtr bfont;
1621     FSFpePtr    conn = (FSFpePtr) fpe->private;
1622     fsQueryXBitmaps16Req bitreq;
1623 
1624 
1625     bfont = (FSBlockedFontPtr) blockrec->data;
1626 
1627     /* send the request */
1628     bitreq.reqType = FS_QueryXBitmaps16;
1629     bitreq.fid = bfont->fontid;
1630     bitreq.format = bfont->format;
1631     bitreq.range = TRUE;
1632     bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
1633     bitreq.num_ranges = 0;
1634 
1635     blockrec->sequence_number = conn->current_seq;
1636     _fs_add_req_log(conn, FS_QueryXBitmaps16);
1637     _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
1638 
1639     return Successful;
1640 }
1641 
1642 /* ARGSUSED */
1643 static int
fs_open_font(client,fpe,flags,name,namelen,format,fmask,id,ppfont,alias,non_cachable_font)1644 fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont,
1645 	     alias, non_cachable_font)
1646     pointer     client;
1647     FontPathElementPtr fpe;
1648     Mask        flags;
1649     char       *name;
1650     fsBitmapFormat format;
1651     fsBitmapFormatMask fmask;
1652     int         namelen;
1653     XID         id;
1654     FontPtr    *ppfont;
1655     char      **alias;
1656     FontPtr     non_cachable_font;	/* Not used in this FPE */
1657 {
1658     FSFpePtr    conn = (FSFpePtr) fpe->private;
1659     FSBlockDataPtr blockrec;
1660     FSBlockedFontPtr blockedfont;
1661     int         err;
1662 
1663     /* libfont interface expects ImageRectMin glyphs */
1664     format = format & ~BitmapFormatImageRectMask | BitmapFormatImageRectMin;
1665 
1666     *alias = (char *) 0;
1667     /* XX if we find the blockrec for the font */
1668     blockrec = (FSBlockDataPtr) conn->blocked_requests;
1669     while (blockrec != (FSBlockDataPtr) 0) {
1670 	if (blockrec->type == FS_OPEN_FONT &&
1671 		blockrec->client == client) {
1672 	    blockedfont = (FSBlockedFontPtr) blockrec->data;
1673 	    err = blockedfont->errcode;
1674 	    if (err == Successful) {
1675 		*ppfont = blockedfont->pfont;
1676 	    } else {
1677 		_fs_cleanup_font(blockedfont);
1678 	    }
1679 	    /* cleanup */
1680 	    _fs_remove_block_rec(conn, blockrec);
1681 	    return err;
1682 	}
1683 	blockrec = blockrec->next;
1684     }
1685     return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
1686 			     id, ppfont);
1687 }
1688 
1689 /* ARGSUSED */
1690 static int
fs_send_close_font(fpe,id)1691 fs_send_close_font(fpe, id)
1692     FontPathElementPtr fpe;
1693     Font        id;
1694 {
1695     FSFpePtr    conn = (FSFpePtr) fpe->private;
1696     fsCloseReq  req;
1697 
1698     /* tell the font server to close the font */
1699     req.reqType = FS_CloseFont;
1700     req.length = SIZEOF(fsCloseReq) >> 2;
1701     req.id = id;
1702     _fs_add_req_log(conn, FS_CloseFont);
1703     _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
1704 
1705     return Successful;
1706 }
1707 
1708 /* ARGSUSED */
1709 static int
fs_close_font(fpe,pfont)1710 fs_close_font(fpe, pfont)
1711     FontPathElementPtr fpe;
1712     FontPtr     pfont;
1713 {
1714     FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate;
1715     FSFpePtr    conn = (FSFpePtr) fpe->private;
1716 
1717     /* XXX we may get called after the resource DB has been cleaned out */
1718     if (find_old_font(fsd->fontid))
1719 	DeleteFontClientID(fsd->fontid);
1720     if (conn->generation == fsd->generation)
1721 	fs_send_close_font(fpe, fsd->fontid);
1722     (*pfont->unload_font) (pfont);
1723 
1724 
1725     xfree(fsd->name);
1726     xfree(fsd);
1727     xfree(pfont->info.isStringProp);
1728     xfree(pfont->info.props);
1729     xfree(pfont->devPrivates);
1730     xfree(pfont);
1731 
1732 
1733     return Successful;
1734 }
1735 
1736 static int
fs_read_glyphs(fpe,blockrec)1737 fs_read_glyphs(fpe, blockrec)
1738     FontPathElementPtr fpe;
1739     FSBlockDataPtr blockrec;
1740 {
1741     FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr) blockrec->data;
1742     FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
1743     FSFpePtr    conn = (FSFpePtr) fpe->private;
1744     FontPtr pfont = bglyph->pfont;      /* works for either blocked font
1745 					   or glyph rec...  pfont is at
1746 					   the very beginning of both
1747 					   blockrec->data structures */
1748     FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate);
1749     FSFontPtr   fsdata = (FSFontPtr) pfont->fontPrivate;
1750     FontInfoPtr	pfi = &pfont->info;
1751     fsQueryXBitmaps16Reply rep;
1752     fsOffset32   *ppbits;
1753     fsOffset32	local_off;
1754     char	*off_adr;
1755     pointer     pbitmaps;
1756     char	*bits;
1757     int         glyph_size,
1758                 offset_size,
1759                 i,
1760 		err;
1761     int		nranges = 0;
1762     fsRange	*ranges, *nextrange;
1763     unsigned long minchar, maxchar;
1764 
1765     /* get reply header */
1766     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
1767     if (rep.type == FS_Error) {
1768 /* XXX -- translate FS error */
1769 	_fs_eat_rest_of_error(conn, (fsError *) & rep);
1770 	err = AllocError;
1771 	goto bail;
1772     }
1773     if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
1774 	      SIZEOF(fsQueryXBitmaps16Reply) - SIZEOF(fsGenericReply)) == -1) {
1775 	if (blockrec->type == FS_OPEN_FONT)
1776 	    fs_free_font(bfont);
1777 	return StillWorking;
1778     }
1779     /* allocate space for glyphs */
1780     offset_size = SIZEOF(fsOffset32) * (rep.num_chars);
1781     glyph_size = (rep.length << 2) - SIZEOF(fsQueryXBitmaps16Reply)
1782 	- offset_size;
1783     ppbits = (fsOffset32 *) xalloc(offset_size);
1784     pbitmaps = (pointer) xalloc(glyph_size);
1785     if (glyph_size && !pbitmaps || !ppbits)
1786     {
1787 	xfree(pbitmaps);
1788 	xfree(ppbits);
1789 
1790 	/* clear wire */
1791 	(void) _fs_drain_bytes_pad(conn, offset_size);
1792 	(void) _fs_drain_bytes_pad(conn, glyph_size);
1793 
1794 	if (blockrec->type == FS_OPEN_FONT)
1795 	    _fs_cleanup_font(bfont);
1796 	err = AllocError;
1797 	goto bail;
1798     }
1799 
1800     /* read offsets */
1801     if (_fs_read_pad(conn, (char *) ppbits, offset_size) == -1) {
1802 	if (blockrec->type == FS_OPEN_FONT)
1803 	    fs_free_font(bfont);
1804 	return StillWorking;
1805     }
1806 
1807     /* read glyphs */
1808     if (_fs_read_pad(conn, (char *) pbitmaps, glyph_size) == -1) {
1809 	if (blockrec->type == FS_OPEN_FONT)
1810 	    fs_free_font(bfont);
1811 	return StillWorking;
1812     }
1813 
1814     if (blockrec->type == FS_LOAD_GLYPHS)
1815     {
1816 	nranges = bglyph->num_expected_ranges;
1817 	nextrange = ranges = bglyph->expected_ranges;
1818     }
1819 
1820     /* place the incoming glyphs */
1821     if (nranges)
1822     {
1823 	/* We're operating under the assumption that the ranges
1824 	   requested in the LoadGlyphs call were all legal for this
1825 	   font, and that individual ranges do not cover multiple
1826 	   rows...  fs_build_range() is designed to ensure this. */
1827 	minchar = (nextrange->min_char_high - pfi->firstRow) *
1828 		  (pfi->lastCol - pfi->firstCol + 1) +
1829 		  nextrange->min_char_low - pfi->firstCol;
1830 	maxchar = (nextrange->max_char_high - pfi->firstRow) *
1831 		  (pfi->lastCol - pfi->firstCol + 1) +
1832 		  nextrange->max_char_low - pfi->firstCol;
1833 	nextrange++;
1834     }
1835     else
1836     {
1837 	minchar = 0;
1838 	maxchar = rep.num_chars;
1839     }
1840 
1841     off_adr = (char *)ppbits;
1842     for (i = 0; i < rep.num_chars; i++)
1843     {
1844 	memcpy(&local_off, off_adr, SIZEOF(fsOffset32));	/* align it */
1845 	if (blockrec->type == FS_OPEN_FONT ||
1846 	    fsdata->encoding[minchar].bits == &_fs_glyph_requested)
1847 	{
1848 	    if (local_off.length)
1849 	    {
1850 		bits = (char *)xalloc(local_off.length);
1851 		if (bits == NULL)
1852 		{
1853 		    xfree(ppbits);
1854 		    xfree(pbitmaps);
1855 		    err = AllocError;
1856 		    goto bail;
1857 		}
1858 		memcpy(bits, pbitmaps + local_off.position,
1859 		       local_off.length);
1860 	    }
1861 	    else if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
1862 		bits = &_fs_glyph_zero_length;
1863 	    else
1864 		bits = 0;
1865 	    if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
1866 		fsd->glyphs_to_get--;
1867 	    fsdata->encoding[minchar].bits = bits;
1868 	}
1869 	if (minchar++ == maxchar)
1870 	{
1871 	    if (!--nranges) break;
1872 	    minchar = (nextrange->min_char_high - pfi->firstRow) *
1873 		      (pfi->lastCol - pfi->firstCol + 1) +
1874 		      nextrange->min_char_low - pfi->firstCol;
1875 	    maxchar = (nextrange->max_char_high - pfi->firstRow) *
1876 		      (pfi->lastCol - pfi->firstCol + 1) +
1877 		      nextrange->max_char_low - pfi->firstCol;
1878 	    nextrange++;
1879 	}
1880 	off_adr += SIZEOF(fsOffset32);
1881     }
1882 
1883     xfree(ppbits);
1884     xfree(pbitmaps);
1885 
1886     if (blockrec->type == FS_OPEN_FONT)
1887     {
1888 	fsd->glyphs_to_get = 0;
1889 	bfont->state = FS_DONE_REPLY;
1890     }
1891     err = Successful;
1892 
1893 bail:
1894     if (blockrec->type == FS_LOAD_GLYPHS)
1895     {
1896 	bglyph->done = TRUE;
1897 	bglyph->errcode = err;
1898     }
1899 
1900     return err;
1901 }
1902 
1903 
1904 
1905 static int
fs_send_load_glyphs(client,pfont,nranges,ranges)1906 fs_send_load_glyphs(client, pfont, nranges, ranges)
1907     pointer     client;
1908     FontPtr     pfont;
1909     int		nranges;
1910     fsRange	*ranges;
1911 {
1912     FSBlockedGlyphPtr blockedglyph;
1913     fsQueryXBitmaps16Req req;
1914     FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate);
1915     FontPathElementPtr fpe = fsd->fpe;
1916     FSFpePtr    conn = (FSFpePtr) fpe->private;
1917     FSBlockDataPtr blockrec;
1918 
1919     /* make a new block record, and add it to the end of the list */
1920     blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
1921     if (!blockrec)
1922 	return AllocError;
1923     blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
1924     blockedglyph->pfont = pfont;
1925     blockedglyph->num_expected_ranges = nranges;
1926     /* Assumption: it's our job to free ranges */
1927     blockedglyph->expected_ranges = ranges;
1928     blockedglyph->done = FALSE;
1929     blockedglyph->clients_depending = (FSClientsDependingPtr)0;
1930 
1931     blockrec->sequence_number = conn->current_seq;
1932 
1933     /* send the request */
1934     req.reqType = FS_QueryXBitmaps16;
1935     req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
1936     req.format = pfont->format;
1937     if (pfont->info.terminalFont)
1938 	req.format = req.format & ~(BitmapFormatImageRectMask) |
1939 		     BitmapFormatImageRectMax;
1940     req.range = TRUE;
1941     /* each range takes up 4 bytes */
1942     req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
1943     req.num_ranges = nranges * 2;	/* protocol wants count of fsChar2bs */
1944     _fs_add_req_log(conn, FS_QueryXBitmaps16);
1945     _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
1946 
1947     /* Send ranges to the server... pack into a char array by hand
1948        to avoid structure-packing portability problems and to
1949        handle swapping for version1 protocol */
1950     if (nranges)
1951     {
1952 #define RANGE_BUFFER_SIZE 64
1953 #define RANGE_BUFFER_SIZE_MASK 63
1954 	int i;
1955 	char range_buffer[RANGE_BUFFER_SIZE * 4];
1956 	char *range_buffer_p;
1957 
1958 	range_buffer_p = range_buffer;
1959 	for (i = 0; i < nranges;)
1960 	{
1961 	    if (conn->fsMajorVersion > 1)
1962 	    {
1963 		*range_buffer_p++ = ranges[i].min_char_high;
1964 		*range_buffer_p++ = ranges[i].min_char_low;
1965 		*range_buffer_p++ = ranges[i].max_char_high;
1966 		*range_buffer_p++ = ranges[i].max_char_low;
1967 	    }
1968 	    else
1969 	    {
1970 		*range_buffer_p++ = ranges[i].min_char_low;
1971 		*range_buffer_p++ = ranges[i].min_char_high;
1972 		*range_buffer_p++ = ranges[i].max_char_low;
1973 		*range_buffer_p++ = ranges[i].max_char_high;
1974 	    }
1975 
1976 	    if (!(++i & RANGE_BUFFER_SIZE_MASK))
1977 	    {
1978 		_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
1979 		range_buffer_p = range_buffer;
1980 	    }
1981 	}
1982 	if (i &= RANGE_BUFFER_SIZE_MASK)
1983 	    _fs_write(conn, range_buffer, i * 4);
1984     }
1985 
1986     return Suspended;
1987 }
1988 
1989 
1990 int
fs_load_all_glyphs(pfont)1991 fs_load_all_glyphs(pfont)
1992     FontPtr	pfont;
1993 {
1994     extern pointer serverClient;	/* This could be any number that
1995 					   doesn't conflict with existing
1996 					   client values. */
1997     int err;
1998     FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
1999 
2000     /*
2001      * The purpose of this procedure is to load all glyphs in the event
2002      * that we're dealing with someone who doesn't understand the finer
2003      * points of glyph caching...  it is called from _fs_get_glyphs() if
2004      * the latter is called to get glyphs that have not yet been loaded.
2005      * We assume that the caller will not know how to handle a return
2006      * value of Suspended (usually the case for a GetGlyphs() caller),
2007      * so this procedure hangs around, freezing the server, for the
2008      * request to complete.  This is an unpleasant kluge called to
2009      * perform an unpleasant job that, we hope, will never be required.
2010      */
2011 
2012     while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) ==
2013 	   Suspended)
2014     {
2015 	fd_set TempSelectMask;
2016 	if (_fs_wait_for_readable(conn) == -1)
2017 	{
2018 	    /* We lost our connection.  Don't wait to reestablish it;
2019 	       just give up. */
2020 	    _fs_connection_died(conn);
2021 
2022 	    /* Get rid of blockrec */
2023 	    fs_client_died(serverClient, pfont->fpe);
2024 
2025 	    return BadCharRange;	/* As good an error as any other */
2026 	}
2027 	FD_SET(conn->fs_fd, &TempSelectMask);
2028 	fs_wakeup(pfont->fpe, &TempSelectMask);
2029     }
2030 
2031     return err;
2032 }
2033 
2034 
2035 int
_fs_load_glyphs(client,pfont,range_flag,nchars,item_size,data)2036 _fs_load_glyphs(client, pfont, range_flag, nchars, item_size, data)
2037     pointer     client;
2038     FontPtr     pfont;
2039     Bool	range_flag;
2040     unsigned int nchars;
2041     int         item_size;
2042     unsigned char *data;
2043 {
2044 
2045     int		nranges = 0;
2046     fsRange     *ranges = NULL;
2047     int         res;
2048     FSBlockDataPtr blockrec;
2049     FSBlockedGlyphPtr blockedglyph;
2050     FSFpePtr    conn = (FSFpePtr) pfont->fpe->private;
2051     FSClientsDependingPtr *clients_depending = NULL;
2052 
2053     /* see if the result is already there */
2054 
2055     blockrec = (FSBlockDataPtr) conn->blocked_requests;
2056     while (blockrec) {
2057 	if (blockrec->type == FS_LOAD_GLYPHS)
2058 	{
2059 	    blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2060 	    if (blockedglyph->pfont == pfont)
2061 	    {
2062 		if (blockrec->client == client)
2063 		{
2064 		    if (blockedglyph->done)
2065 		    {
2066 			int errcode = blockedglyph->errcode;
2067 			signal_clients_depending(&blockedglyph->
2068 						 clients_depending);
2069 			_fs_remove_block_rec(conn, blockrec);
2070 			return errcode;
2071 		    }
2072 		    else return Suspended;
2073 		}
2074 		/* We've found an existing LoadGlyphs blockrec for this
2075 		   font but for another client.  Rather than build a
2076 		   blockrec for it now (which entails some complex
2077 		   maintenance), we'll add it to a queue of clients to
2078 		   be signalled when the existing LoadGlyphs is
2079 		   completed.  */
2080 		clients_depending = &blockedglyph->clients_depending;
2081 		break;
2082 	    }
2083 	}
2084 	else if (blockrec->type == FS_OPEN_FONT)
2085 	{
2086 	    FSBlockedFontPtr bfont;
2087 	    bfont = (FSBlockedFontPtr) blockrec->data;
2088 	    if (bfont->pfont == pfont)
2089 	    {
2090 		if (blockrec->client == client)
2091 		{
2092 		    if (bfont->state == FS_DONE_REPLY)
2093 		    {
2094 			int errcode = bfont->errcode;
2095 			signal_clients_depending(&bfont->clients_depending);
2096 			_fs_remove_block_rec(conn, blockrec);
2097 			if (errcode == Successful) break;
2098 			else return errcode;
2099 		    }
2100 		    else return Suspended;
2101 		}
2102 		/* We've found an existing OpenFont blockrec for this
2103 		   font but for another client.  Rather than build a
2104 		   blockrec for it now (which entails some complex
2105 		   maintenance), we'll add it to a queue of clients to
2106 		   be signalled when the existing OpenFont is
2107 		   completed.  */
2108 		if (bfont->state != FS_DONE_REPLY)
2109 		{
2110 		    clients_depending = &bfont->clients_depending;
2111 		    break;
2112 		}
2113 	    }
2114 	}
2115 
2116 	blockrec = blockrec->next;
2117     }
2118 
2119     /*
2120      * see if the desired glyphs already exist, and return Successful if they
2121      * do, otherwise build up character range/character string
2122      */
2123     res = fs_build_range(pfont, range_flag, nchars, item_size, data,
2124 			 &nranges, &ranges);
2125 
2126     switch (res)
2127     {
2128 	case AccessDone:
2129 	    return Successful;
2130 
2131 	case Successful:
2132 	    break;
2133 
2134 	default:
2135 	    return res;
2136     }
2137 
2138     /*
2139      * If clients_depending is not null, this request must wait for
2140      * some prior request(s) to complete.
2141      */
2142     if (clients_depending)
2143     {
2144 	/* Since we're not ready to send the load_glyphs request yet,
2145 	   clean up the damage (if any) caused by the fs_build_range()
2146 	   call. */
2147 	if (nranges)
2148 	{
2149 	    _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2150 	    xfree(ranges);
2151 	}
2152 	return add_clients_depending(clients_depending, client);
2153     }
2154 
2155     /*
2156      * If fsd->generation != conn->generation, the font has been closed
2157      * due to a lost connection.  We will reopen it, which will result
2158      * in one of three things happening:
2159      *	 1) The open will succeed and obtain the same font.  Life
2160      *	    is wonderful.
2161      *	 2) The open will fail.  There is code above to recognize this
2162      *	    and flunk the LoadGlyphs request.  The client might not be
2163      *	    thrilled.
2164      *	 3) Worst case: the open will succeed but the font we open will
2165      *	    be different.  The fs_read_query_info() procedure attempts
2166      *	    to detect this by comparing the existing metrics and
2167      *	    properties against those of the reopened font... if they
2168      *	    don't match, we flunk the reopen, which eventually results
2169      *	    in flunking the LoadGlyphs request.  We could go a step
2170      *	    further and compare the extents, but this should be
2171      *	    sufficient.
2172      */
2173     if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
2174     {
2175 	/* Since we're not ready to send the load_glyphs request yet,
2176 	   clean up the damage caused by the fs_build_range() call. */
2177 	_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2178 	xfree(ranges);
2179 
2180 	/* Now try to reopen the font. */
2181 	return fs_send_open_font(client, (FontPathElementPtr)0,
2182 				 (Mask)FontReopen, (char *)0, 0,
2183 				 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
2184 				 (XID)0, &pfont);
2185     }
2186 
2187     return fs_send_load_glyphs(client, pfont, nranges, ranges);
2188 }
2189 
2190 
2191 
2192 static int
fs_read_list(fpe,blockrec)2193 fs_read_list(fpe, blockrec)
2194     FontPathElementPtr fpe;
2195     FSBlockDataPtr blockrec;
2196 {
2197     FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data;
2198     FSFpePtr    conn = (FSFpePtr) fpe->private;
2199     fsListFontsReply rep;
2200     char       *data,
2201                *dp;
2202     int         length,
2203                 i;
2204 
2205     blist->done = TRUE;
2206 
2207     /* read reply header */
2208     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
2209     if (rep.type == FS_Error) {
2210 /* XXX -- translate FS error */
2211 	_fs_eat_rest_of_error(conn, (fsError *) & rep);
2212 	return AllocError;
2213     }
2214     if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
2215 		 SIZEOF(fsListFontsReply) - SIZEOF(fsGenericReply)) == -1) {
2216 	/* nothing to free (i think) */
2217 	return StillWorking;
2218     }
2219     length = (rep.length << 2) - SIZEOF(fsListFontsReply);
2220     data = (char *) xalloc(length);
2221     if (!data) {
2222 	_fs_drain_bytes_pad(conn, length);
2223 	return AllocError;
2224     }
2225     /* read the list */
2226     if (_fs_read_pad(conn, data, length) == -1) {
2227 	/* nothing to free (i think) */
2228 	return StillWorking;
2229     }
2230     /* copy data into FontPathRecord */
2231     dp = data;
2232     for (i = 0; i < rep.nFonts; i++) {
2233 	length = *(unsigned char *)dp++;
2234 	if (AddFontNamesName(blist->names, dp, length) != Successful) {
2235 	    blist->errcode = AllocError;
2236 	    break;
2237 	}
2238 	dp += length;
2239     }
2240 
2241     xfree(data);
2242     return Successful;
2243 }
2244 
2245 static int
fs_send_list_fonts(client,fpe,pattern,patlen,maxnames,newnames)2246 fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames)
2247     pointer     client;
2248     FontPathElementPtr fpe;
2249     char       *pattern;
2250     int         patlen;
2251     int         maxnames;
2252     FontNamesPtr newnames;
2253 {
2254     FSBlockDataPtr blockrec;
2255     FSBlockedListPtr blockedlist;
2256     FSFpePtr    conn = (FSFpePtr) fpe->private;
2257     fsListFontsReq req;
2258 
2259     _fs_client_access (conn, client, FALSE);
2260     _fs_client_resolution(conn);
2261 
2262     /* make a new block record, and add it to the end of the list */
2263     blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
2264     if (!blockrec)
2265 	return AllocError;
2266     blockedlist = (FSBlockedListPtr) blockrec->data;
2267     blockedlist->patlen = patlen;
2268     blockedlist->errcode = Successful;
2269     blockedlist->names = newnames;
2270     blockedlist->done = FALSE;
2271 
2272     /* send the request */
2273     req.reqType = FS_ListFonts;
2274     req.maxNames = maxnames;
2275     req.nbytes = patlen;
2276     req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
2277     _fs_add_req_log(conn, FS_ListFonts);
2278     _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
2279     _fs_write_pad(conn, (char *) pattern, patlen);
2280 
2281 #ifdef NCD
2282     if (configData.ExtendedFontDiags) {
2283 	char        buf[256];
2284 
2285 	memcpy(buf, pattern, MIN(256, patlen));
2286 	buf[MIN(256, patlen)] = '\0';
2287 	printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
2288 	       buf, fpe->name);
2289     }
2290 #endif
2291 
2292     return Suspended;
2293 }
2294 
2295 static int
fs_list_fonts(client,fpe,pattern,patlen,maxnames,newnames)2296 fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames)
2297     pointer     client;
2298     FontPathElementPtr fpe;
2299     char       *pattern;
2300     int         patlen;
2301     int         maxnames;
2302     FontNamesPtr newnames;
2303 {
2304     FSBlockDataPtr blockrec;
2305     FSBlockedListPtr blockedlist;
2306     FSFpePtr    conn = (FSFpePtr) fpe->private;
2307     int         err;
2308 
2309     /* see if the result is already there */
2310     blockrec = (FSBlockDataPtr) conn->blocked_requests;
2311     while (blockrec) {
2312 	if (blockrec->type == FS_LIST_FONTS && blockrec->client == client) {
2313 	    blockedlist = (FSBlockedListPtr) blockrec->data;
2314 	    if (blockedlist->patlen == patlen && blockedlist->done) {
2315 		err = blockedlist->errcode;
2316 		_fs_remove_block_rec(conn, blockrec);
2317 		return err;
2318 	    }
2319 	}
2320 	blockrec = blockrec->next;
2321     }
2322 
2323     /* didn't find waiting record, so send a new one */
2324     return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
2325 }
2326 
2327 static int  padlength[4] = {0, 3, 2, 1};
2328 
2329 static int
fs_read_list_info(fpe,blockrec)2330 fs_read_list_info(fpe, blockrec)
2331     FontPathElementPtr fpe;
2332     FSBlockDataPtr blockrec;
2333 {
2334     FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data;
2335     fsListFontsWithXInfoReply rep;
2336     FSFpePtr    conn = (FSFpePtr) fpe->private;
2337     fsPropInfo  pi;
2338     fsPropOffset *po;
2339     char       *name;
2340     pointer     pd;
2341     int		err;
2342 
2343     /* clean up anything from the last trip */
2344     if (binfo->name)
2345     {
2346 	xfree(binfo->name);
2347 	binfo->name = NULL;
2348     }
2349     if (binfo->pfi) {
2350 	xfree(binfo->pfi->isStringProp);
2351 	xfree(binfo->pfi->props);
2352 	xfree(binfo->pfi);
2353 	binfo->pfi = NULL;
2354     }
2355     /* get reply header */
2356     memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply));
2357     if (rep.type == FS_Error) {
2358 /* XXX -- translate FS error */
2359 	_fs_eat_rest_of_error(conn, (fsError *) & rep);
2360 	binfo->errcode = AllocError;
2361 	return AllocError;
2362     }
2363     if (conn->fsMajorVersion > 1)
2364 	if (rep.nameLength == 0)
2365 	    goto done;
2366     /* old protocol sent a full-length reply even for the last one */
2367     if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply),
2368 	  SIZEOF(fsListFontsWithXInfoReply) - SIZEOF(fsGenericReply)) == -1) {
2369 	goto done;
2370     }
2371     if (rep.nameLength == 0)
2372 	goto done;
2373 
2374     /* read the data */
2375     name = (char *) xalloc(rep.nameLength);
2376     binfo->pfi = (FontInfoPtr) xalloc(sizeof(FontInfoRec));
2377     if (!name || !binfo->pfi) {
2378 	xfree(name);
2379 	xfree(binfo->pfi);
2380 	binfo->pfi = NULL;
2381 	_fs_drain_bytes(conn,
2382 			rep.length - (SIZEOF(fsListFontsWithXInfoReply) -
2383 				      SIZEOF(fsGenericReply)));
2384 	binfo->errcode = AllocError;
2385 	return AllocError;
2386     }
2387     if (conn->fsMajorVersion == 1)
2388 	if (_fs_read_pad(conn, name, rep.nameLength) == -1)
2389 	    goto done;
2390     if (_fs_read_pad(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1)
2391 	    goto done;
2392 
2393     po = (fsPropOffset *) xalloc(SIZEOF(fsPropOffset) * pi.num_offsets);
2394     pd = (pointer) xalloc(pi.data_len);
2395     if (!po || !pd) {
2396 	xfree(name);
2397 	xfree(po);
2398 	xfree(pd);
2399 	xfree (binfo->pfi);
2400 	binfo->pfi = NULL;
2401 	binfo->errcode = AllocError;
2402 	return AllocError;
2403     }
2404     err = _fs_read_pad(conn, (char *) po,
2405 		       (pi.num_offsets * SIZEOF(fsPropOffset)));
2406     if (err != -1)
2407     {
2408 	if (conn->fsMajorVersion > 1)
2409 	    err = _fs_read(conn, (char *) pd, pi.data_len);
2410 	else
2411 	    err = _fs_read_pad(conn, (char *) pd, pi.data_len);
2412     }
2413     if (err != -1  &&  conn->fsMajorVersion != 1)
2414     {
2415 	err = _fs_read(conn, name, rep.nameLength);
2416 	if (err != -1)
2417 	    err = _fs_drain_bytes(conn, padlength[(pi.data_len+rep.nameLength)&3]);
2418     }
2419 
2420     if (err == -1) {
2421 	xfree(name);
2422 	xfree(po);
2423 	xfree(pd);
2424 	xfree (binfo->pfi);
2425 	binfo->pfi = NULL;
2426 	goto done;
2427     }
2428 
2429     if (_fs_convert_lfwi_reply(conn, binfo->pfi, &rep, &pi, po, pd) != Successful)
2430     {
2431 	xfree(name);
2432 	xfree(po);
2433 	xfree(pd);
2434 	xfree (binfo->pfi);
2435 	binfo->pfi = NULL;
2436 	goto done;
2437     }
2438     xfree(po);
2439     xfree(pd);
2440     binfo->name = name;
2441     binfo->namelen = rep.nameLength;
2442     binfo->remaining = rep.nReplies;
2443 
2444     binfo->status = FS_LFWI_REPLY;
2445     binfo->errcode = Suspended;
2446     /* disable this font server until we've processed this response */
2447     FD_CLR(conn->fs_fd, &_fs_fd_mask);
2448 
2449     return Successful;
2450 
2451 done:
2452     binfo->status = FS_LFWI_FINISHED;
2453     binfo->errcode = BadFontName;
2454     binfo->name = (char *) 0;
2455     return Successful;
2456 }
2457 
2458 /* ARGSUSED */
2459 static int
fs_start_list_with_info(client,fpe,pattern,len,maxnames,pdata)2460 fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata)
2461     pointer     client;
2462     FontPathElementPtr fpe;
2463     char       *pattern;
2464     int         len;
2465     int         maxnames;
2466     pointer    *pdata;
2467 {
2468     FSBlockDataPtr blockrec;
2469     FSBlockedListInfoPtr blockedinfo;
2470     fsListFontsWithXInfoReq req;
2471     FSFpePtr    conn = (FSFpePtr) fpe->private;
2472 
2473     _fs_client_access (conn, client, FALSE);
2474     _fs_client_resolution(conn);
2475 
2476     /* make a new block record, and add it to the end of the list */
2477     blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
2478     if (!blockrec)
2479 	return AllocError;
2480     blockedinfo = (FSBlockedListInfoPtr) blockrec->data;
2481     bzero((char *) blockedinfo, sizeof(FSBlockedListInfoRec));
2482     blockedinfo->status = FS_LFWI_WAITING;
2483     blockedinfo->errcode = Suspended;
2484 
2485     /* send the request */
2486     req.reqType = FS_ListFontsWithXInfo;
2487     req.maxNames = maxnames;
2488     req.nbytes = len;
2489     req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
2490     _fs_add_req_log(conn, FS_ListFontsWithXInfo);
2491     (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
2492     (void) _fs_write_pad(conn, pattern, len);
2493 
2494 #ifdef NCD
2495     if (configData.ExtendedFontDiags) {
2496 	char        buf[256];
2497 
2498 	memcpy(buf, pattern, MIN(256, len));
2499 	buf[MIN(256, len)] = '\0';
2500 	printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
2501 	       buf, fpe->name);
2502     }
2503 #endif
2504 
2505     return Successful;
2506 }
2507 
2508 /* ARGSUSED */
2509 static int
fs_next_list_with_info(client,fpe,namep,namelenp,pFontInfo,numFonts,private)2510 fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts,
2511 		       private)
2512     pointer     client;
2513     FontPathElementPtr fpe;
2514     char      **namep;
2515     int        *namelenp;
2516     FontInfoPtr *pFontInfo;
2517     int        *numFonts;
2518     pointer     private;
2519 {
2520     FSBlockDataPtr blockrec;
2521     FSBlockedListInfoPtr blockedinfo;
2522     FSFpePtr    conn = (FSFpePtr) fpe->private;
2523 
2524     /* see if the result is already there */
2525     blockrec = (FSBlockDataPtr) conn->blocked_requests;
2526     while (blockrec) {
2527 	if (blockrec->type == FS_LIST_WITH_INFO &&
2528 		blockrec->client == client) {
2529 	    blockedinfo = (FSBlockedListInfoPtr) blockrec->data;
2530 	    break;
2531 	}
2532 	blockrec = blockrec->next;
2533     }
2534 
2535     if (!blockrec)
2536     {
2537 	/* The only good reason for not finding a blockrec would be if
2538 	   disconnect/reconnect to the font server wiped it out and the
2539 	   code that called us didn't do the right thing to create
2540 	   another one.  Under those circumstances, we need to return an
2541 	   error to prevent that code from attempting to interpret the
2542 	   information we don't return.  */
2543 	return BadFontName;
2544     }
2545 
2546     if (blockedinfo->status == FS_LFWI_WAITING)
2547 	return Suspended;
2548 
2549     *namep = blockedinfo->name;
2550     *namelenp = blockedinfo->namelen;
2551     *pFontInfo = blockedinfo->pfi;
2552     *numFonts = blockedinfo->remaining;
2553     FD_SET(conn->fs_fd, &_fs_fd_mask);
2554     if (blockedinfo->status == FS_LFWI_FINISHED) {
2555 	int         err = blockedinfo->errcode;
2556 
2557 	_fs_remove_block_rec(conn, blockrec);
2558 	return err;
2559     }
2560     if (blockedinfo->status == FS_LFWI_REPLY) {
2561 	blockedinfo->status = FS_LFWI_WAITING;
2562 	return Successful;
2563     } else {
2564 	return blockedinfo->errcode;
2565     }
2566 }
2567 
2568 /*
2569  * Called when client exits
2570  */
2571 
2572 static void
fs_client_died(client,fpe)2573 fs_client_died(client, fpe)
2574     pointer     client;
2575     FontPathElementPtr fpe;
2576 {
2577     FSFpePtr    conn = (FSFpePtr) fpe->private;
2578     FSBlockDataPtr blockrec,
2579                 depending;
2580     FSClientPtr	*prev, cur;
2581     fsFreeACReq	freeac;
2582 
2583     for (prev = &conn->clients; cur = *prev; prev = &cur->next)
2584     {
2585 	if (cur->client == client) {
2586 	    freeac.reqType = FS_FreeAC;
2587 	    freeac.id = cur->acid;
2588 	    freeac.length = sizeof (fsFreeACReq) >> 2;
2589 	    _fs_add_req_log(conn, FS_FreeAC);
2590 	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2591 	    *prev = cur->next;
2592 	    xfree (cur);
2593 	    break;
2594 	}
2595     }
2596     /* see if the result is already there */
2597     blockrec = (FSBlockDataPtr) conn->blocked_requests;
2598     while (blockrec) {
2599 	if (blockrec->client == client)
2600 	    break;
2601 	blockrec = blockrec->next;
2602     }
2603     if (!blockrec)
2604 	return;
2605     if (blockrec->type == FS_LIST_WITH_INFO)
2606     {
2607 	FSBlockedListInfoPtr binfo;
2608 	binfo = (FSBlockedListInfoPtr) blockrec->data;
2609 	if (binfo->status == FS_LFWI_REPLY)
2610 	    FD_SET(conn->fs_fd, &_fs_fd_mask);
2611     	if (binfo->name)
2612 	{
2613 	    xfree(binfo->name);
2614 	    binfo->name = NULL;
2615 	}
2616     	if (binfo->pfi)
2617 	{
2618 	    xfree(binfo->pfi->isStringProp);
2619 	    xfree(binfo->pfi->props);
2620 	    xfree(binfo->pfi);
2621 	    binfo->pfi = NULL;
2622     	}
2623     }
2624     /* replace the client pointers in this block rec with the chained one */
2625     if (depending = blockrec->depending) {
2626 	blockrec->client = depending->client;
2627 	blockrec->depending = depending->depending;
2628 	blockrec = depending;
2629     }
2630     fs_abort_blockrec(conn, blockrec);
2631 }
2632 
2633 static void
_fs_client_access(conn,client,sync)2634 _fs_client_access (conn, client, sync)
2635     FSFpePtr	conn;
2636     pointer	client;
2637     Bool	sync;
2638 {
2639     FSClientPtr	*prev,	    cur;
2640     fsCreateACReq	    crac;
2641     fsSetAuthorizationReq   setac;
2642     fsGenericReply	    rep;
2643     char		    *authorizations;
2644     int			    authlen;
2645     Bool		    new_cur = FALSE;
2646 
2647     for (prev = &conn->clients; cur = *prev; prev = &cur->next)
2648     {
2649 	if (cur->client == client)
2650 	{
2651 	    if (prev != &conn->clients)
2652 	    {
2653 		*prev = cur->next;
2654 		cur->next = conn->clients;
2655 		conn->clients = cur;
2656 	    }
2657 	    break;
2658 	}
2659     }
2660     if (!cur)
2661     {
2662 	cur = (FSClientPtr) xalloc (sizeof (FSClientRec));
2663 	if (!cur)
2664 	    return;
2665 	cur->client = client;
2666 	cur->next = conn->clients;
2667 	conn->clients = cur;
2668 	cur->acid = GetNewFontClientID ();
2669 	new_cur = TRUE;
2670     }
2671     if (new_cur || cur->auth_generation != client_auth_generation(client))
2672     {
2673 	if (!new_cur)
2674 	{
2675 	    fsFreeACReq	freeac;
2676 	    freeac.reqType = FS_FreeAC;
2677 	    freeac.id = cur->acid;
2678 	    freeac.length = sizeof (fsFreeACReq) >> 2;
2679 	    _fs_add_req_log(conn, FS_FreeAC);
2680 	    _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2681 	}
2682 	crac.reqType = FS_CreateAC;
2683 	crac.num_auths = set_font_authorizations(&authorizations, &authlen,
2684 						 client);
2685 	authlen = crac.num_auths ? (authlen + 3) & ~0x3 : 0;
2686 	crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
2687 	crac.acid = cur->acid;
2688 	_fs_add_req_log(conn, FS_CreateAC);
2689 	_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
2690 	_fs_write(conn, authorizations, authlen);
2691 	/* if we're synchronous, open_font will be confused by
2692 	 * the reply; eat it and continue
2693 	 */
2694 	if (sync)
2695 	{
2696 	    if (_fs_read(conn, (char *) &rep, sizeof (fsGenericReply)) == -1)
2697 		return;
2698 	    fs_handle_unexpected(conn, &rep);
2699 	}
2700 	/* ignore reply; we don't even care about it */
2701 	conn->curacid = 0;
2702 	cur->auth_generation = client_auth_generation(client);
2703     }
2704     if (conn->curacid != cur->acid)
2705     {
2706     	setac.reqType = FS_SetAuthorization;
2707     	setac.length = sizeof (fsSetAuthorizationReq) >> 2;
2708     	setac.id = cur->acid;
2709     	_fs_add_req_log(conn, FS_SetAuthorization);
2710     	_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
2711 	conn->curacid = cur->acid;
2712     }
2713 }
2714 
2715 /*
2716  * called at server init time
2717  */
2718 
2719 void
fs_register_fpe_functions()2720 fs_register_fpe_functions()
2721 {
2722     fs_font_type = RegisterFPEFunctions(fs_name_check,
2723 					fs_init_fpe,
2724 					fs_free_fpe,
2725 					fs_reset_fpe,
2726 					fs_open_font,
2727 					fs_close_font,
2728 					fs_list_fonts,
2729 					fs_start_list_with_info,
2730 					fs_next_list_with_info,
2731 					fs_wakeup,
2732 					fs_client_died,
2733 					_fs_load_glyphs,
2734 					(int (*))0,
2735 					(int (*))0,
2736 					(void (*))0);
2737 }
2738 
2739 static int
check_fs_open_font(client,fpe,flags,name,namelen,format,fmask,id,ppfont,alias,non_cachable_font)2740 check_fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont,
2741 	     alias, non_cachable_font)
2742     pointer     client;
2743     FontPathElementPtr fpe;
2744     Mask        flags;
2745     char       *name;
2746     fsBitmapFormat format;
2747     fsBitmapFormatMask fmask;
2748     int         namelen;
2749     XID         id;
2750     FontPtr    *ppfont;
2751     char      **alias;
2752     FontPtr     non_cachable_font;	/* Not used in this FPE */
2753 {
2754     if (XpClientIsBitmapClient(client))
2755 	return (fs_open_font(client, fpe, flags, name, namelen, format,
2756 			fmask, id, ppfont, alias, non_cachable_font) );
2757     return BadFontName;
2758 }
2759 
2760 static int
check_fs_list_fonts(client,fpe,pattern,patlen,maxnames,newnames)2761 check_fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames)
2762     pointer     client;
2763     FontPathElementPtr fpe;
2764     char       *pattern;
2765     int         patlen;
2766     int         maxnames;
2767     FontNamesPtr newnames;
2768 {
2769     if (XpClientIsBitmapClient(client))
2770 	return (fs_list_fonts(client, fpe, pattern, patlen, maxnames,
2771 		newnames));
2772     return BadFontName;
2773 }
2774 
2775 static int
check_fs_start_list_with_info(client,fpe,pattern,len,maxnames,pdata)2776 check_fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata)
2777     pointer     client;
2778     FontPathElementPtr fpe;
2779     char       *pattern;
2780     int         len;
2781     int         maxnames;
2782     pointer    *pdata;
2783 {
2784     if (XpClientIsBitmapClient(client))
2785 	return (fs_start_list_with_info(client, fpe, pattern, len, maxnames,
2786 		pdata));
2787     return BadFontName;
2788 }
2789 
2790 static int
check_fs_next_list_with_info(client,fpe,namep,namelenp,pFontInfo,numFonts,private)2791 check_fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts,
2792 		       private)
2793     pointer     client;
2794     FontPathElementPtr fpe;
2795     char      **namep;
2796     int        *namelenp;
2797     FontInfoPtr *pFontInfo;
2798     int        *numFonts;
2799     pointer     private;
2800 {
2801     if (XpClientIsBitmapClient(client))
2802 	return (fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo,
2803 		numFonts,private));
2804     return BadFontName;
2805 }
2806 
2807 void
check_fs_register_fpe_functions()2808 check_fs_register_fpe_functions()
2809 {
2810     fs_font_type = RegisterFPEFunctions(fs_name_check,
2811 					fs_init_fpe,
2812 					fs_free_fpe,
2813 					fs_reset_fpe,
2814 					check_fs_open_font,
2815 					fs_close_font,
2816 					check_fs_list_fonts,
2817 					check_fs_start_list_with_info,
2818 					check_fs_next_list_with_info,
2819 					fs_wakeup,
2820 					fs_client_died,
2821 					_fs_load_glyphs,
2822 					(int (*))0,
2823 					(int (*))0,
2824 					(void (*))0);
2825 }
2826