#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef WIN32
#define _WILLWINSOCK_
#endif
#define FONT_t
#define TRANS_CLIENT
#include "X11/Xtrans/Xtrans.h"
#include "X11/Xpoll.h"
#include <X11/fonts/FS.h>
#include <X11/fonts/FSproto.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/fonts/fontmisc.h>
#include <X11/fonts/fontstruct.h>
#include "fservestr.h"
#include <X11/fonts/fontutil.h>
#include <errno.h>
#include <time.h>
#define Time_t time_t
#ifdef NCD
#include <ncd/nvram.h>
#endif
#include <stddef.h>
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#define TimeCmp(a,c,b) ((int) ((a) - (b)) c 0)
#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
(pci)->rightSideBearing || \
(pci)->ascent || \
(pci)->descent || \
(pci)->characterWidth)
extern void ErrorF(const char *f, ...);
static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
static int fs_read_list_info ( FontPathElementPtr fpe,
FSBlockDataPtr blockrec );
extern fd_set _fs_fd_mask;
static void fs_block_handler ( pointer data, OSTimePtr wt,
pointer LastSelectMask );
static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
static FSFpePtr fs_fpes;
static CARD32 fs_blockState;
static int _fs_restart_connection ( FSFpePtr conn );
static void fs_send_query_bitmaps ( FontPathElementPtr fpe,
FSBlockDataPtr blockrec );
static int fs_send_close_font ( FontPathElementPtr fpe, Font id );
static void fs_client_died ( pointer client, FontPathElementPtr fpe );
static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
static void _fs_client_resolution ( FSFpePtr conn );
static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
static int fs_await_reply (FSFpePtr conn);
static void _fs_do_blocked (FSFpePtr conn);
static void fs_cleanup_bfont (FSBlockedFontPtr bfont);
char _fs_glyph_undefined;
char _fs_glyph_requested;
static char _fs_glyph_zero_length;
static int generationCount;
static int FontServerRequestTimeout = 30 * 1000;
static void
_fs_close_server (FSFpePtr conn);
static FSFpePtr
_fs_init_conn (char *servername);
static int
_fs_wait_connect (FSFpePtr conn);
static int
_fs_send_init_packets (FSFpePtr conn);
static void
_fs_check_reconnect (FSFpePtr conn);
static void
_fs_start_reconnect (FSFpePtr conn);
static void
_fs_free_conn (FSFpePtr conn);
static int
fs_free_fpe(FontPathElementPtr fpe);
#ifdef DEBUG
static void
_fs_add_req_log(FSFpePtr conn, int opcode)
{
conn->current_seq++;
fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
conn->current_seq, opcode);
conn->reqbuffer[conn->reqindex].opcode = opcode;
conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
conn->reqindex++;
if (conn->reqindex == REQUEST_LOG_SIZE)
conn->reqindex = 0;
}
static void
_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
{
int i;
for (i = 0; i < REQUEST_LOG_SIZE; i++)
if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
break;
if (i == REQUEST_LOG_SIZE)
fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: unknown\n",
rep->sequenceNumber);
else
fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: %d\n",
rep->sequenceNumber,
conn->reqbuffer[i].opcode);
}
#else
#define _fs_add_req_log(conn,op) ((conn)->current_seq++)
#define _fs_add_rep_log(conn,rep)
#endif
static Bool
fs_name_check(char *name)
{
return (name && *name != '/' && strchr(name, '/'));
}
static void
_fs_client_resolution(FSFpePtr conn)
{
fsSetResolutionReq srreq;
int num_res;
FontResolutionPtr res;
res = GetClientResolutions(&num_res);
if (num_res) {
srreq.reqType = FS_SetResolution;
srreq.num_resolutions = num_res;
srreq.length = (SIZEOF(fsSetResolutionReq) +
(num_res * SIZEOF(fsResolution)) + 3) >> 2;
_fs_add_req_log(conn, FS_SetResolution);
if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
(void)_fs_write_pad(conn, (char *) res,
(num_res * SIZEOF(fsResolution)));
}
}
static void
fs_close_conn(FSFpePtr conn)
{
FSClientPtr client, nclient;
_fs_close_server (conn);
for (client = conn->clients; client; client = nclient)
{
nclient = client->next;
free (client);
}
conn->clients = NULL;
}
static int
fs_init_fpe(FontPathElementPtr fpe)
{
FSFpePtr conn;
char *name;
int err;
int ret;
name = fpe->name;
if (*name == ':')
name++;
conn = _fs_init_conn (name);
if (!conn)
err = AllocError;
else
{
err = init_fs_handlers (fpe, fs_block_handler);
if (err != Successful)
{
_fs_free_conn (conn);
err = AllocError;
}
else
{
fpe->private = conn;
conn->next = fs_fpes;
fs_fpes = conn;
ret = _fs_wait_connect (conn);
if (ret != FSIO_READY)
{
fs_free_fpe (fpe);
err = BadFontPath;
}
else
err = Successful;
}
}
if (err == Successful)
{
#ifdef NCD
if (configData.ExtendedFontDiags)
printf("Connected to font server \"%s\"\n", name);
#endif
#ifdef DEBUG
fprintf (stderr, "connected to FS \"%s\"\n", name);
#endif
}
else
{
#ifdef DEBUG
fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
#endif
#ifdef NCD
if (configData.ExtendedFontDiags)
printf("Failed to connect to font server \"%s\"\n", name);
#endif
;
}
return err;
}
static int
fs_reset_fpe(FontPathElementPtr fpe)
{
(void) _fs_send_init_packets((FSFpePtr) fpe->private);
return Successful;
}
static int
fs_free_fpe(FontPathElementPtr fpe)
{
FSFpePtr conn = (FSFpePtr) fpe->private, *prev;
for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
{
if (*prev == conn)
{
*prev = conn->next;
break;
}
}
_fs_unmark_block (conn, conn->blockState);
fs_close_conn(conn);
remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
_fs_free_conn (conn);
fpe->private = (pointer) 0;
#ifdef NCD
if (configData.ExtendedFontDiags)
printf("Disconnected from font server \"%s\"\n", fpe->name);
#endif
#ifdef DEBUG
fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
#endif
return Successful;
}
static FSBlockDataPtr
fs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
{
FSBlockDataPtr blockrec,
*prev;
FSFpePtr conn = (FSFpePtr) fpe->private;
int size;
switch (type) {
case FS_OPEN_FONT:
size = sizeof(FSBlockedFontRec);
break;
case FS_LOAD_GLYPHS:
size = sizeof(FSBlockedGlyphRec);
break;
case FS_LIST_FONTS:
size = sizeof(FSBlockedListRec);
break;
case FS_LIST_WITH_INFO:
size = sizeof(FSBlockedListInfoRec);
break;
default:
size = 0;
break;
}
blockrec = malloc(sizeof(FSBlockDataRec) + size);
if (!blockrec)
return (FSBlockDataPtr) 0;
blockrec->data = (pointer) (blockrec + 1);
blockrec->client = client;
blockrec->sequenceNumber = -1;
blockrec->errcode = StillWorking;
blockrec->type = type;
blockrec->depending = 0;
blockrec->next = (FSBlockDataPtr) 0;
for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
;
*prev = blockrec;
return blockrec;
}
static void
_fs_set_pending_reply (FSFpePtr conn)
{
FSBlockDataPtr blockrec;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
if (blockrec->errcode == StillWorking)
break;
if (blockrec)
{
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
_fs_mark_block (conn, FS_PENDING_REPLY);
}
else
_fs_unmark_block (conn, FS_PENDING_REPLY);
}
static void
_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
{
FSBlockDataPtr *prev;
for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
if (*prev == blockrec)
{
*prev = blockrec->next;
break;
}
if (blockrec->type == FS_LOAD_GLYPHS)
{
FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
if (bglyph->num_expected_ranges)
free(bglyph->expected_ranges);
}
free(blockrec);
_fs_set_pending_reply (conn);
}
static void
_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
{
FSClientsDependingPtr p;
while ((p = *clients_depending))
{
*clients_depending = p->next;
ClientSignal(p->client);
free(p);
}
}
static int
_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
{
FSClientsDependingPtr new, cd;
for (; (cd = *clients_depending);
clients_depending = &(*clients_depending)->next)
{
if (cd->client == client)
return Suspended;
}
new = malloc (sizeof (FSClientsDependingRec));
if (!new)
return BadAlloc;
new->client = client;
new->next = 0;
*clients_depending = new;
return Suspended;
}
static void
_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
{
switch(blockrec->type) {
case FS_OPEN_FONT: {
FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
fs_cleanup_bfont (bfont);
_fs_signal_clients_depending(&bfont->clients_depending);
break;
}
case FS_LOAD_GLYPHS: {
FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
_fs_clean_aborted_loadglyphs(bglyph->pfont,
bglyph->num_expected_ranges,
bglyph->expected_ranges);
_fs_signal_clients_depending(&bglyph->clients_depending);
break;
}
case FS_LIST_FONTS:
break;
case FS_LIST_WITH_INFO: {
FSBlockedListInfoPtr binfo;
binfo = (FSBlockedListInfoPtr) blockrec->data;
if (binfo->status == FS_LFWI_REPLY)
FD_SET(conn->fs_fd, &_fs_fd_mask);
_fs_free_props (&binfo->info);
}
default:
break;
}
}
static void
fs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
{
_fs_clean_aborted_blockrec (conn, blockrec);
_fs_remove_block_rec (conn, blockrec);
}
static void
fs_cleanup_bfont (FSBlockedFontPtr bfont)
{
FSFontDataRec *fsd;
if (bfont->pfont)
{
fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
if (!(bfont->flags & FontReopen))
{
if (bfont->freeFont)
(*bfont->pfont->unload_font) (bfont->pfont);
#ifdef DEBUG
else
fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
#endif
bfont->pfont = 0;
}
else
fsd->generation = -1;
}
}
static fsGenericReply *
fs_get_reply (FSFpePtr conn, int *error)
{
char *buf;
fsGenericReply *rep;
int ret;
if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
{
*error = FSIO_BLOCK;
return 0;
}
ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
if (ret != FSIO_READY)
{
*error = FSIO_BLOCK;
return 0;
}
rep = (fsGenericReply *) buf;
ret = _fs_start_read (conn, rep->length << 2, &buf);
if (ret != FSIO_READY)
{
*error = FSIO_BLOCK;
return 0;
}
*error = FSIO_READY;
return (fsGenericReply *) buf;
}
static Bool
fs_reply_ready (FSFpePtr conn)
{
fsGenericReply *rep;
if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
return FALSE;
if (fs_data_read (conn) < sizeof (fsGenericReply))
return FALSE;
rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
if (fs_data_read (conn) < rep->length << 2)
return FALSE;
return TRUE;
}
static void
_fs_pending_reply (FSFpePtr conn)
{
if (!(conn->blockState & FS_PENDING_REPLY))
{
_fs_mark_block (conn, FS_PENDING_REPLY);
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
}
}
static void
_fs_prepare_for_reply (FSFpePtr conn)
{
_fs_pending_reply (conn);
_fs_flush (conn);
}
static int
fs_await_reply (FSFpePtr conn)
{
int ret;
if (conn->blockState & FS_COMPLETE_REPLY)
return FSIO_READY;
while (!fs_get_reply (conn, &ret))
{
if (ret != FSIO_BLOCK)
return ret;
if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
{
_fs_connection_died (conn);
return FSIO_ERROR;
}
}
return FSIO_READY;
}
static int
fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
fsOpenBitmapFontReply *rep;
FSBlockDataPtr blockOrig;
FSBlockedFontPtr origBfont;
int ret;
rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
if (rep)
_fs_done_read (conn, rep->length << 2);
fs_cleanup_bfont (bfont);
return BadFontName;
}
if (rep->otherid && !(bfont->flags & FontReopen))
{
fs_cleanup_bfont (bfont);
bfont->pfont = find_old_font(rep->otherid);
bfont->freeFont = FALSE;
bfont->fontid = rep->otherid;
bfont->state = FS_DONE_REPLY;
for (blockOrig = conn->blockedRequests;
blockOrig;
blockOrig = blockOrig->next)
{
if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
{
origBfont = (FSBlockedFontPtr) blockOrig->data;
if (origBfont->fontid == rep->otherid)
{
blockrec->depending = blockOrig->depending;
blockOrig->depending = blockrec;
bfont->state = FS_DEPENDING;
bfont->pfont = origBfont->pfont;
break;
}
}
}
if (bfont->pfont == NULL)
{
ret = BadFontName;
}
else
ret = AccessDone;
}
else
{
bfont->pfont->info.cachable = rep->cachable != 0;
bfont->state = FS_INFO_REPLY;
blockrec->sequenceNumber = bfont->queryInfoSequence;
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
ret = StillWorking;
}
_fs_done_read (conn, rep->length << 2);
return ret;
}
static Bool
fs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
{
int i;
if (pInfo1->firstCol != pInfo2->firstCol ||
pInfo1->lastCol != pInfo2->lastCol ||
pInfo1->firstRow != pInfo2->firstRow ||
pInfo1->lastRow != pInfo2->lastRow ||
pInfo1->defaultCh != pInfo2->defaultCh ||
pInfo1->noOverlap != pInfo2->noOverlap ||
pInfo1->terminalFont != pInfo2->terminalFont ||
pInfo1->constantMetrics != pInfo2->constantMetrics ||
pInfo1->constantWidth != pInfo2->constantWidth ||
pInfo1->inkInside != pInfo2->inkInside ||
pInfo1->inkMetrics != pInfo2->inkMetrics ||
pInfo1->allExist != pInfo2->allExist ||
pInfo1->drawDirection != pInfo2->drawDirection ||
pInfo1->cachable != pInfo2->cachable ||
pInfo1->anamorphic != pInfo2->anamorphic ||
pInfo1->maxOverlap != pInfo2->maxOverlap ||
pInfo1->fontAscent != pInfo2->fontAscent ||
pInfo1->fontDescent != pInfo2->fontDescent ||
pInfo1->nprops != pInfo2->nprops)
return FALSE;
#define MATCH(xci1, xci2) \
(((xci1).leftSideBearing == (xci2).leftSideBearing) && \
((xci1).rightSideBearing == (xci2).rightSideBearing) && \
((xci1).characterWidth == (xci2).characterWidth) && \
((xci1).ascent == (xci2).ascent) && \
((xci1).descent == (xci2).descent) && \
((xci1).attributes == (xci2).attributes))
if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
!MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
!MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
!MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
return FALSE;
#undef MATCH
for (i = 0; i < pInfo1->nprops; i++)
if (pInfo1->isStringProp[i] !=
pInfo2->isStringProp[i] ||
pInfo1->props[i].name !=
pInfo2->props[i].name ||
pInfo1->props[i].value !=
pInfo2->props[i].value)
{
return FALSE;
}
return TRUE;
}
static int
fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
FSFpePtr conn = (FSFpePtr) fpe->private;
fsQueryXInfoReply *rep;
char *buf;
fsPropInfo *pi;
fsPropOffset *po;
pointer pd;
FontInfoPtr pInfo;
FontInfoRec tempInfo;
int err;
int ret;
rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
if (rep)
_fs_done_read (conn, rep->length << 2);
fs_cleanup_bfont (bfont);
return BadFontName;
}
if (bfont->flags & FontReopen)
pInfo = &tempInfo;
else
pInfo = &bfont->pfont->info;
buf = (char *) rep;
buf += SIZEOF(fsQueryXInfoReply);
fsUnpack_XFontInfoHeader(rep, pInfo);
_fs_init_fontinfo(conn, pInfo);
pi = (fsPropInfo *) buf;
buf += SIZEOF (fsPropInfo);
po = (fsPropOffset *) buf;
buf += pi->num_offsets * SIZEOF(fsPropOffset);
pd = (pointer) buf;
buf += pi->data_len;
ret = _fs_convert_props(pi, po, pd, pInfo);
_fs_done_read (conn, rep->length << 2);
if (ret == -1)
{
fs_cleanup_bfont (bfont);
return AllocError;
}
if (bfont->flags & FontReopen)
{
if (fs_fonts_match (pInfo, &bfont->pfont->info))
{
err = Successful;
bfont->state = FS_DONE_REPLY;
}
else
{
fs_cleanup_bfont (bfont);
err = BadFontName;
}
_fs_free_props (pInfo);
return err;
}
if (bfont->pfont->info.terminalFont)
bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
BitmapFormatImageRectMax);
if (glyphCachingMode == CACHING_OFF ||
(glyphCachingMode == CACHE_16_BIT_GLYPHS
&& !bfont->pfont->info.lastRow))
{
bfont->flags |= FontLoadAll;
}
if (bfont->flags & FontLoadBitmaps)
{
fs_send_query_bitmaps (fpe, blockrec);
_fs_flush (conn);
}
bfont->state = FS_EXTENT_REPLY;
blockrec->sequenceNumber = bfont->queryExtentsSequence;
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
return StillWorking;
}
static int
fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
fsQueryXExtents16Reply *rep;
char *buf;
int i;
int numExtents;
int numInfos;
int ret;
Bool haveInk = FALSE;
CharInfoPtr ci, pCI;
char *fsci;
fsXCharInfo fscilocal;
FontInfoRec *fi = &bfont->pfont->info;
rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
if (rep)
_fs_done_read (conn, rep->length << 2);
fs_cleanup_bfont (bfont);
return BadFontName;
}
numExtents = rep->num_extents;
numInfos = numExtents;
if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
{
numInfos *= 2;
haveInk = TRUE;
}
ci = pCI = malloc(sizeof(CharInfoRec) * numInfos);
if (!pCI)
{
_fs_done_read (conn, rep->length << 2);
fs_cleanup_bfont(bfont);
return AllocError;
}
fsfont->encoding = pCI;
if (haveInk)
fsfont->inkMetrics = pCI + numExtents;
else
fsfont->inkMetrics = pCI;
buf = (char *) rep;
buf += SIZEOF (fsQueryXExtents16Reply);
fsci = buf;
fsd->glyphs_to_get = 0;
ci = fsfont->inkMetrics;
for (i = 0; i < numExtents; i++)
{
memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo));
_fs_convert_char_info(&fscilocal, &ci->metrics);
if (ci->metrics.ascent > fi->maxbounds.ascent)
{
ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
fpe->name, fsd->name,
ci->metrics.ascent, fi->maxbounds.ascent);
ci->metrics.ascent = fi->maxbounds.ascent;
}
if (ci->metrics.descent > fi->maxbounds.descent)
{
ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
fpe->name, fsd->name,
ci->metrics.descent, fi->maxbounds.descent);
ci->metrics.descent = fi->maxbounds.descent;
}
fsci = fsci + SIZEOF(fsXCharInfo);
if (NONZEROMETRICS(&ci->metrics))
{
if (!haveInk &&
(ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
ci->metrics.ascent == -ci->metrics.descent))
pCI[i].bits = &_fs_glyph_zero_length;
else
{
pCI[i].bits = &_fs_glyph_undefined;
fsd->glyphs_to_get++;
}
}
else
pCI[i].bits = (char *)0;
ci++;
}
_fs_done_read (conn, rep->length << 2);
if (haveInk)
{
CharInfoPtr ii;
ci = fsfont->encoding;
ii = fsfont->inkMetrics;
for (i = 0; i < numExtents; i++, ci++, ii++)
{
if (NONZEROMETRICS(&ii->metrics))
{
ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
ci->metrics.ascent = FONT_MAX_ASCENT(fi);
ci->metrics.descent = FONT_MAX_DESCENT(fi);
ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
ci->metrics.attributes = ii->metrics.attributes;
}
else
{
ci->metrics = ii->metrics;
}
if (ci->metrics.ascent > fi->maxbounds.ascent)
{
ErrorF("fserve: warning: %s %s ascent (%d) "
"> maxascent (%d)\n",
fpe->name, fsd->name,
ci->metrics.ascent, fi->maxbounds.ascent);
ci->metrics.ascent = fi->maxbounds.ascent;
}
if (ci->metrics.descent > fi->maxbounds.descent)
{
ErrorF("fserve: warning: %s %s descent (%d) "
"> maxdescent (%d)\n",
fpe->name, fsd->name,
ci->metrics.descent, fi->maxbounds.descent);
ci->metrics.descent = fi->maxbounds.descent;
}
}
}
{
unsigned int r, c, numCols, firstCol;
firstCol = bfont->pfont->info.firstCol;
numCols = bfont->pfont->info.lastCol - firstCol + 1;
c = bfont->pfont->info.defaultCh;
fsfont->pDefault = 0;
if (bfont->pfont->info.lastRow)
{
r = c >> 8;
r -= bfont->pfont->info.firstRow;
c &= 0xff;
c -= firstCol;
if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
c < numCols)
fsfont->pDefault = &pCI[r * numCols + c];
}
else
{
c -= firstCol;
if (c < numCols)
fsfont->pDefault = &pCI[c];
}
}
bfont->state = FS_GLYPHS_REPLY;
if (bfont->flags & FontLoadBitmaps)
{
blockrec->sequenceNumber = bfont->queryBitmapsSequence;
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
return StillWorking;
}
return Successful;
}
#ifdef DEBUG
static char *fs_open_states[] = {
"OPEN_REPLY ",
"INFO_REPLY ",
"EXTENT_REPLY",
"GLYPHS_REPLY",
"DONE_REPLY ",
"DEPENDING ",
};
#endif
static int
fs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
int err;
#ifdef DEBUG
fprintf (stderr, "fs_do_open_font state %s %s\n",
fs_open_states[bfont->state],
((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
#endif
err = BadFontName;
switch (bfont->state) {
case FS_OPEN_REPLY:
err = fs_read_open_font(fpe, blockrec);
if (err != StillWorking) {
switch (bfont->state) {
case FS_DONE_REPLY:
err = Successful;
break;
case FS_DEPENDING:
err = StillWorking;
break;
}
}
break;
case FS_INFO_REPLY:
err = fs_read_query_info(fpe, blockrec);
break;
case FS_EXTENT_REPLY:
err = fs_read_extent_info(fpe, blockrec);
break;
case FS_GLYPHS_REPLY:
if (bfont->flags & FontLoadBitmaps)
err = fs_read_glyphs(fpe, blockrec);
break;
case FS_DEPENDING:
default:
break;
}
#ifdef DEBUG
fprintf (stderr, "fs_do_open_font err %d\n", err);
#endif
if (err != StillWorking)
{
bfont->state = FS_DONE_REPLY;
while ((blockrec = blockrec->depending))
{
bfont = (FSBlockedFontPtr) blockrec->data;
bfont->state = FS_DONE_REPLY;
}
}
return err;
}
void
_fs_mark_block (FSFpePtr conn, CARD32 mask)
{
conn->blockState |= mask;
fs_blockState |= mask;
}
void
_fs_unmark_block (FSFpePtr conn, CARD32 mask)
{
FSFpePtr c;
if (conn->blockState & mask)
{
conn->blockState &= ~mask;
fs_blockState = 0;
for (c = fs_fpes; c; c = c->next)
fs_blockState |= c->blockState;
}
}
static void
fs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
{
static struct timeval block_timeout;
CARD32 now, earliest, wakeup;
int soonest;
FSFpePtr conn;
XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
&_fs_fd_mask);
if (fs_blockState & FS_PENDING_WRITE)
for (conn = fs_fpes; conn; conn = conn->next)
if (conn->blockState & FS_PENDING_WRITE)
_fs_flush (conn);
if (fs_blockState & FS_COMPLETE_REPLY)
{
block_timeout.tv_sec = 0;
block_timeout.tv_usec = 0;
if (*wt == NULL)
*wt = &block_timeout;
else
**wt = block_timeout;
}
else if (fs_blockState & (FS_BROKEN_WRITE|
FS_BROKEN_CONNECTION|
FS_PENDING_REPLY|
FS_RECONNECTING))
{
now = GetTimeInMillis ();
earliest = now + 10000000;
for (conn = fs_fpes; conn; conn = conn->next)
{
if (conn->blockState & FS_RECONNECTING)
{
wakeup = conn->blockedConnectTime;
if (TimeCmp (wakeup, <, earliest))
earliest = wakeup;
}
if (conn->blockState & FS_BROKEN_CONNECTION)
{
wakeup = conn->brokenConnectionTime;
if (TimeCmp (wakeup, <, earliest))
earliest = wakeup;
}
if (conn->blockState & FS_BROKEN_WRITE)
{
wakeup = conn->brokenWriteTime;
if (TimeCmp (wakeup, <, earliest))
earliest = wakeup;
}
if (conn->blockState & FS_PENDING_REPLY)
{
wakeup = conn->blockedReplyTime;
if (TimeCmp (wakeup, <, earliest))
earliest = wakeup;
}
}
soonest = earliest - now;
if (soonest < 0)
soonest = 0;
block_timeout.tv_sec = soonest / 1000;
block_timeout.tv_usec = (soonest % 1000) * 1000;
if (*wt == NULL)
*wt = &block_timeout;
else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
**wt = block_timeout;
}
}
static void
fs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
{
if (rep->type == FS_Event && rep->data1 == KeepAlive)
{
fsNoopReq req;
req.reqType = FS_Noop;
req.length = SIZEOF(fsNoopReq) >> 2;
_fs_add_req_log(conn, FS_Noop);
_fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
}
_fs_done_read (conn, rep->length << 2);
}
static void
fs_read_reply (FontPathElementPtr fpe, pointer client)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
int ret;
int err;
fsGenericReply *rep;
if ((rep = fs_get_reply (conn, &ret)))
{
_fs_add_rep_log (conn, rep);
for (blockrec = conn->blockedRequests;
blockrec;
blockrec = blockrec->next)
{
if (blockrec->sequenceNumber == rep->sequenceNumber)
break;
}
err = Successful;
if (!blockrec)
{
fs_handle_unexpected(conn, rep);
}
else
{
switch (blockrec->type) {
case FS_OPEN_FONT:
blockrec->errcode = fs_do_open_font(fpe, blockrec);
break;
case FS_LOAD_GLYPHS:
blockrec->errcode = fs_read_glyphs(fpe, blockrec);
break;
case FS_LIST_FONTS:
blockrec->errcode = fs_read_list(fpe, blockrec);
break;
case FS_LIST_WITH_INFO:
blockrec->errcode = fs_read_list_info(fpe, blockrec);
break;
default:
break;
}
err = blockrec->errcode;
if (err != StillWorking)
{
while (blockrec)
{
blockrec->errcode = err;
if (client != blockrec->client)
ClientSignal(blockrec->client);
blockrec = blockrec->depending;
}
_fs_unmark_block (conn, FS_PENDING_REPLY);
}
}
if (fs_reply_ready (conn))
_fs_mark_block (conn, FS_COMPLETE_REPLY);
else
_fs_unmark_block (conn, FS_COMPLETE_REPLY);
}
}
static int
fs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
{
fd_set *LastSelectMask = (fd_set *) mask;
FSFpePtr conn = (FSFpePtr) fpe->private;
if ((conn->blockState & FS_RECONNECTING))
_fs_check_reconnect (conn);
else if ((conn->blockState & FS_COMPLETE_REPLY) ||
(conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
fs_read_reply (fpe, 0);
if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
_fs_do_blocked (conn);
#ifdef DEBUG
{
FSBlockDataPtr blockrec;
FSBlockedFontPtr bfont;
FSBlockedListPtr blist;
static CARD32 lastState;
static FSBlockDataPtr lastBlock;
if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
{
fprintf (stderr, " Block State 0x%x\n", (int) conn->blockState);
lastState = conn->blockState;
lastBlock = conn->blockedRequests;
}
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
{
switch (blockrec->type) {
case FS_OPEN_FONT:
bfont = (FSBlockedFontPtr) blockrec->data;
fprintf (stderr, " Blocked font errcode %d sequence %d state %s %s\n",
blockrec->errcode,
blockrec->sequenceNumber,
fs_open_states[bfont->state],
bfont->pfont ?
((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
"<freed>");
break;
case FS_LIST_FONTS:
blist = (FSBlockedListPtr) blockrec->data;
fprintf (stderr, " Blocked list errcode %d sequence %d\n",
blockrec->errcode, blockrec->sequenceNumber);
break;
default:
fprintf (stderr, " Blocked type %d errcode %d sequence %d\n",
blockrec->type,
blockrec->errcode,
blockrec->sequenceNumber);
break;
}
}
}
#endif
return FALSE;
}
void
_fs_connection_died(FSFpePtr conn)
{
if (conn->blockState & FS_BROKEN_CONNECTION)
return;
fs_close_conn(conn);
conn->brokenConnectionTime = GetTimeInMillis ();
_fs_mark_block (conn, FS_BROKEN_CONNECTION);
_fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
}
static int
_fs_restart_connection(FSFpePtr conn)
{
FSBlockDataPtr block;
_fs_unmark_block (conn, FS_GIVE_UP);
while ((block = (FSBlockDataPtr) conn->blockedRequests))
{
if (block->errcode == StillWorking)
{
ClientSignal(block->client);
fs_abort_blockrec(conn, block);
}
}
return TRUE;
}
static void
_fs_giveup (FSFpePtr conn)
{
FSBlockDataPtr block;
if (conn->blockState & FS_GIVE_UP)
return;
#ifdef DEBUG
fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
#endif
_fs_mark_block (conn, FS_GIVE_UP);
while ((block = (FSBlockDataPtr) conn->blockedRequests))
{
if (block->errcode == StillWorking)
{
ClientSignal (block->client);
fs_abort_blockrec (conn, block);
}
}
if (conn->fs_fd >= 0)
_fs_connection_died (conn);
}
static void
_fs_do_blocked (FSFpePtr conn)
{
CARD32 now;
now = GetTimeInMillis ();
if ((conn->blockState & FS_PENDING_REPLY) &&
TimeCmp (conn->blockedReplyTime, <=, now))
{
_fs_giveup (conn);
}
else
{
if (conn->blockState & FS_BROKEN_CONNECTION)
{
if (TimeCmp (conn->brokenConnectionTime, <=, now))
_fs_start_reconnect (conn);
}
else if (conn->blockState & FS_BROKEN_WRITE)
{
if (TimeCmp (conn->brokenWriteTime, <=, now))
_fs_flush (conn);
}
}
}
static int
fs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
char *name, int namelen,
fsBitmapFormat format, fsBitmapFormatMask fmask,
XID id, FontPtr *ppfont)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FontPtr font;
FSBlockDataPtr blockrec = NULL;
FSBlockedFontPtr bfont;
FSFontDataPtr fsd;
fsOpenBitmapFontReq openreq;
fsQueryXInfoReq inforeq;
fsQueryXExtents16Req extreq;
int err;
unsigned char buf[1024];
if (conn->blockState & FS_GIVE_UP)
return BadFontName;
if (namelen <= 0 || namelen > sizeof (buf) - 1)
return BadFontName;
if (flags & FontReopen)
{
Atom nameatom, fn = None;
int i;
font = *ppfont;
fsd = (FSFontDataPtr)font->fpePrivate;
if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
{
for (i = 0; i < font->info.nprops; i++)
if (font->info.props[i].name == nameatom &&
font->info.isStringProp[i])
{
fn = font->info.props[i].value;
break;
}
}
if (fn == None || !(name = NameForAtom(fn)))
{
name = fsd->name;
namelen = fsd->namelen;
}
else
namelen = strlen(name);
}
else
{
font = fs_create_font (fpe, name, namelen, format, fmask);
if (!font)
return AllocError;
fsd = (FSFontDataPtr)font->fpePrivate;
}
blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
if (!blockrec)
{
if (!(flags & FontReopen))
(*font->unload_font) (font);
return AllocError;
}
if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
{
_fs_pending_reply (conn);
return Suspended;
}
fsd->generation = conn->generation;
bfont = (FSBlockedFontPtr) blockrec->data;
bfont->fontid = fsd->fontid;
bfont->pfont = font;
bfont->state = FS_OPEN_REPLY;
bfont->flags = flags;
bfont->format = fsd->format;
bfont->clients_depending = (FSClientsDependingPtr)0;
bfont->freeFont = (flags & FontReopen) == 0;
_fs_client_access (conn, client, (flags & FontOpenSync) != 0);
_fs_client_resolution(conn);
buf[0] = (unsigned char) namelen;
memcpy(&buf[1], name, namelen);
openreq.reqType = FS_OpenBitmapFont;
openreq.pad = 0;
openreq.fid = fsd->fontid;
openreq.format_hint = fsd->format;
openreq.format_mask = fsd->fmask;
openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
_fs_add_req_log(conn, FS_OpenBitmapFont);
_fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
_fs_write_pad(conn, (char *) buf, namelen + 1);
blockrec->sequenceNumber = conn->current_seq;
inforeq.reqType = FS_QueryXInfo;
inforeq.pad = 0;
inforeq.id = fsd->fontid;
inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
bfont->queryInfoSequence = conn->current_seq + 1;
_fs_add_req_log(conn, FS_QueryXInfo);
_fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
if (!(bfont->flags & FontReopen))
{
extreq.reqType = FS_QueryXExtents16;
extreq.range = fsTrue;
extreq.fid = fsd->fontid;
extreq.num_ranges = 0;
extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
bfont->queryExtentsSequence = conn->current_seq + 1;
_fs_add_req_log(conn, FS_QueryXExtents16);
_fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
}
#ifdef NCD
if (configData.ExtendedFontDiags)
{
memcpy(buf, name, MIN(256, namelen));
buf[MIN(256, namelen)] = '\0';
printf("Requesting font \"%s\" from font server \"%s\"\n",
buf, font->fpe->name);
}
#endif
_fs_prepare_for_reply (conn);
err = blockrec->errcode;
if (bfont->flags & FontOpenSync)
{
while (blockrec->errcode == StillWorking)
{
if (fs_await_reply (conn) != FSIO_READY)
{
blockrec->errcode = BadFontName;
break;
}
fs_read_reply (font->fpe, client);
}
err = blockrec->errcode;
if (err == Successful)
*ppfont = bfont->pfont;
else
fs_cleanup_bfont (bfont);
bfont->freeFont = FALSE;
_fs_remove_block_rec (conn, blockrec);
}
return err == StillWorking ? Suspended : err;
}
static void
fs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
fsQueryXBitmaps16Req bitreq;
bitreq.reqType = FS_QueryXBitmaps16;
bitreq.fid = bfont->fontid;
bitreq.format = bfont->format;
bitreq.range = TRUE;
bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
bitreq.num_ranges = 0;
bfont->queryBitmapsSequence = conn->current_seq + 1;
_fs_add_req_log(conn, FS_QueryXBitmaps16);
_fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
}
static int
fs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
char *name, int namelen,
fsBitmapFormat format, fsBitmapFormatMask fmask,
XID id, FontPtr *ppfont,
char **alias, FontPtr non_cachable_font)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
FSBlockedFontPtr bfont;
int err;
format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
*alias = (char *) 0;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
{
if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
{
err = blockrec->errcode;
if (err == StillWorking)
return Suspended;
bfont = (FSBlockedFontPtr) blockrec->data;
if (err == Successful)
*ppfont = bfont->pfont;
else
fs_cleanup_bfont (bfont);
_fs_remove_block_rec (conn, blockrec);
return err;
}
}
return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
id, ppfont);
}
static int
fs_send_close_font(FontPathElementPtr fpe, Font id)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
fsCloseReq req;
if (conn->blockState & FS_GIVE_UP)
return Successful;
req.reqType = FS_CloseFont;
req.pad = 0;
req.length = SIZEOF(fsCloseReq) >> 2;
req.id = id;
_fs_add_req_log(conn, FS_CloseFont);
_fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
return Successful;
}
static void
fs_close_font(FontPathElementPtr fpe, FontPtr pfont)
{
FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate;
FSFpePtr conn = (FSFpePtr) fpe->private;
if (conn->generation == fsd->generation)
fs_send_close_font(fpe, fsd->fontid);
#ifdef DEBUG
{
FSBlockDataPtr blockrec;
FSBlockedFontPtr bfont;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
{
if (blockrec->type == FS_OPEN_FONT)
{
bfont = (FSBlockedFontPtr) blockrec->data;
if (bfont->pfont == pfont)
fprintf (stderr, "closing font which hasn't been opened\n");
}
}
}
#endif
(*pfont->unload_font) (pfont);
}
static int
fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr) blockrec->data;
FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
FSFpePtr conn = (FSFpePtr) fpe->private;
FontPtr pfont = bglyph->pfont;
FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate);
FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate;
FontInfoPtr pfi = &pfont->info;
fsQueryXBitmaps16Reply *rep;
char *buf;
fsOffset32 *ppbits;
fsOffset32 local_off;
char *off_adr;
pointer pbitmaps;
char *bits, *allbits;
#ifdef DEBUG
char *origallbits;
#endif
int i,
err;
int nranges = 0;
int ret;
fsRange *nextrange = 0;
unsigned long minchar, maxchar;
rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
if (rep)
_fs_done_read (conn, rep->length << 2);
err = AllocError;
goto bail;
}
buf = (char *) rep;
buf += SIZEOF (fsQueryXBitmaps16Reply);
ppbits = (fsOffset32 *) buf;
buf += SIZEOF (fsOffset32) * (rep->num_chars);
pbitmaps = (pointer ) buf;
if (blockrec->type == FS_LOAD_GLYPHS)
{
nranges = bglyph->num_expected_ranges;
nextrange = bglyph->expected_ranges;
}
if (nranges)
{
minchar = (nextrange->min_char_high - pfi->firstRow) *
(pfi->lastCol - pfi->firstCol + 1) +
nextrange->min_char_low - pfi->firstCol;
maxchar = (nextrange->max_char_high - pfi->firstRow) *
(pfi->lastCol - pfi->firstCol + 1) +
nextrange->max_char_low - pfi->firstCol;
nextrange++;
}
else
{
minchar = 0;
maxchar = rep->num_chars;
}
off_adr = (char *)ppbits;
allbits = fs_alloc_glyphs (pfont, rep->nbytes);
if (!allbits)
{
err = AllocError;
goto bail;
}
#ifdef DEBUG
origallbits = allbits;
fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
(int) rep->num_chars, (int) rep->nbytes, fsd->name);
#endif
for (i = 0; i < rep->num_chars; i++)
{
memcpy(&local_off, off_adr, SIZEOF(fsOffset32));
if (blockrec->type == FS_OPEN_FONT ||
fsdata->encoding[minchar].bits == &_fs_glyph_requested)
{
if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
{
if (local_off.length)
{
bits = allbits;
allbits += local_off.length;
memcpy(bits, (char *)pbitmaps + local_off.position,
local_off.length);
}
else
bits = &_fs_glyph_zero_length;
}
else
bits = 0;
if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
fsd->glyphs_to_get--;
fsdata->encoding[minchar].bits = bits;
}
if (minchar++ == maxchar)
{
if (!--nranges) break;
minchar = (nextrange->min_char_high - pfi->firstRow) *
(pfi->lastCol - pfi->firstCol + 1) +
nextrange->min_char_low - pfi->firstCol;
maxchar = (nextrange->max_char_high - pfi->firstRow) *
(pfi->lastCol - pfi->firstCol + 1) +
nextrange->max_char_low - pfi->firstCol;
nextrange++;
}
off_adr += SIZEOF(fsOffset32);
}
#ifdef DEBUG
fprintf (stderr, "Used %d bytes instead of %d\n",
(int) (allbits - origallbits), (int) rep->nbytes);
#endif
if (blockrec->type == FS_OPEN_FONT)
{
fsd->glyphs_to_get = 0;
bfont->state = FS_DONE_REPLY;
}
err = Successful;
bail:
_fs_done_read (conn, rep->length << 2);
return err;
}
static int
fs_send_load_glyphs(pointer client, FontPtr pfont,
int nranges, fsRange *ranges)
{
FontPathElementPtr fpe = pfont->fpe;
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockedGlyphPtr blockedglyph;
fsQueryXBitmaps16Req req;
FSBlockDataPtr blockrec;
if (conn->blockState & FS_GIVE_UP)
return BadCharRange;
blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
if (!blockrec)
return AllocError;
blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
blockedglyph->pfont = pfont;
blockedglyph->num_expected_ranges = nranges;
blockedglyph->expected_ranges = ranges;
blockedglyph->clients_depending = (FSClientsDependingPtr)0;
if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
{
_fs_pending_reply (conn);
return Suspended;
}
req.reqType = FS_QueryXBitmaps16;
req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
req.format = pfont->format;
if (pfont->info.terminalFont)
req.format = (req.format & ~(BitmapFormatImageRectMask)) |
BitmapFormatImageRectMax;
req.range = TRUE;
req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
req.num_ranges = nranges * 2;
_fs_add_req_log(conn, FS_QueryXBitmaps16);
_fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
blockrec->sequenceNumber = conn->current_seq;
if (nranges)
{
#define RANGE_BUFFER_SIZE 64
#define RANGE_BUFFER_SIZE_MASK 63
int i;
char range_buffer[RANGE_BUFFER_SIZE * 4];
char *range_buffer_p;
range_buffer_p = range_buffer;
for (i = 0; i < nranges;)
{
if (conn->fsMajorVersion > 1)
{
*range_buffer_p++ = ranges[i].min_char_high;
*range_buffer_p++ = ranges[i].min_char_low;
*range_buffer_p++ = ranges[i].max_char_high;
*range_buffer_p++ = ranges[i].max_char_low;
}
else
{
*range_buffer_p++ = ranges[i].min_char_low;
*range_buffer_p++ = ranges[i].min_char_high;
*range_buffer_p++ = ranges[i].max_char_low;
*range_buffer_p++ = ranges[i].max_char_high;
}
if (!(++i & RANGE_BUFFER_SIZE_MASK))
{
_fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
range_buffer_p = range_buffer;
}
}
if (i &= RANGE_BUFFER_SIZE_MASK)
_fs_write(conn, range_buffer, i * 4);
}
_fs_prepare_for_reply (conn);
return Suspended;
}
extern pointer serverClient;
static int
_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
unsigned int nchars, int item_size, unsigned char *data)
{
FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
int nranges = 0;
fsRange *ranges = NULL;
int res;
FSBlockDataPtr blockrec;
FSBlockedGlyphPtr blockedglyph;
FSClientsDependingPtr *clients_depending = NULL;
int err;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
{
if (blockrec->type == FS_LOAD_GLYPHS)
{
blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
if (blockedglyph->pfont == pfont)
{
if (blockrec->client == client)
{
err = blockrec->errcode;
if (err == StillWorking)
return Suspended;
_fs_signal_clients_depending(&blockedglyph->clients_depending);
_fs_remove_block_rec(conn, blockrec);
return err;
}
clients_depending = &blockedglyph->clients_depending;
break;
}
}
else if (blockrec->type == FS_OPEN_FONT)
{
FSBlockedFontPtr bfont;
bfont = (FSBlockedFontPtr) blockrec->data;
if (bfont->pfont == pfont)
{
if (blockrec->client == client)
{
err = blockrec->errcode;
if (err == StillWorking)
return Suspended;
_fs_signal_clients_depending(&bfont->clients_depending);
_fs_remove_block_rec(conn, blockrec);
if (err != Successful)
return err;
break;
}
if (blockrec->errcode == StillWorking)
{
clients_depending = &bfont->clients_depending;
break;
}
}
}
}
res = fs_build_range(pfont, range_flag, nchars, item_size, data,
&nranges, &ranges);
switch (res)
{
case AccessDone:
return Successful;
case Successful:
break;
default:
return res;
}
if (clients_depending)
{
if (nranges)
{
_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
free(ranges);
}
return _fs_add_clients_depending(clients_depending, client);
}
if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
{
_fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
free(ranges);
return fs_send_open_font(client, pfont->fpe,
(Mask)FontReopen, (char *)0, 0,
(fsBitmapFormat)0, (fsBitmapFormatMask)0,
(XID)0, &pfont);
}
return fs_send_load_glyphs(client, pfont, nranges, ranges);
}
int
fs_load_all_glyphs(FontPtr pfont)
{
int err;
FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) ==
Suspended)
{
if (fs_await_reply (conn) != FSIO_READY)
{
fs_client_died(serverClient, pfont->fpe);
err = BadCharRange;
break;
}
fs_read_reply (pfont->fpe, serverClient);
}
return err;
}
static int
fs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data;
fsListFontsReply *rep;
char *data;
int length,
i,
ret;
int err;
rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
if (rep)
_fs_done_read (conn, rep->length << 2);
return AllocError;
}
data = (char *) rep + SIZEOF (fsListFontsReply);
err = Successful;
for (i = 0; i < rep->nFonts; i++)
{
length = *(unsigned char *)data++;
err = AddFontNamesName(blist->names, data, length);
if (err != Successful)
break;
data += length;
}
_fs_done_read (conn, rep->length << 2);
return err;
}
static int
fs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern,
int patlen, int maxnames, FontNamesPtr newnames)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
FSBlockedListPtr blockedlist;
fsListFontsReq req;
if (conn->blockState & FS_GIVE_UP)
return BadFontName;
blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
if (!blockrec)
return AllocError;
blockedlist = (FSBlockedListPtr) blockrec->data;
blockedlist->names = newnames;
if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
{
_fs_pending_reply (conn);
return Suspended;
}
_fs_client_access (conn, client, FALSE);
_fs_client_resolution(conn);
req.reqType = FS_ListFonts;
req.pad = 0;
req.maxNames = maxnames;
req.nbytes = patlen;
req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
_fs_add_req_log(conn, FS_ListFonts);
_fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
_fs_write_pad(conn, (char *) pattern, patlen);
blockrec->sequenceNumber = conn->current_seq;
#ifdef NCD
if (configData.ExtendedFontDiags) {
char buf[256];
memcpy(buf, pattern, MIN(256, patlen));
buf[MIN(256, patlen)] = '\0';
printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
buf, fpe->name);
}
#endif
_fs_prepare_for_reply (conn);
return Suspended;
}
static int
fs_list_fonts(pointer client, FontPathElementPtr fpe,
char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
int err;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
{
if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
{
err = blockrec->errcode;
if (err == StillWorking)
return Suspended;
_fs_remove_block_rec(conn, blockrec);
return err;
}
}
return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
}
static int
fs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
{
FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data;
fsListFontsWithXInfoReply *rep;
char *buf;
FSFpePtr conn = (FSFpePtr) fpe->private;
fsPropInfo *pi;
fsPropOffset *po;
pointer pd;
int ret;
int err;
_fs_free_props (&binfo->info);
rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
if (!rep || rep->type == FS_Error)
{
if (ret == FSIO_BLOCK)
return StillWorking;
binfo->status = FS_LFWI_FINISHED;
err = AllocError;
goto done;
}
if (rep->nameLength == 0)
{
#ifdef DEBUG
fprintf (stderr, "fs_read_list_info done\n");
#endif
binfo->status = FS_LFWI_FINISHED;
err = BadFontName;
goto done;
}
buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
if (conn->fsMajorVersion <= 1)
{
memcpy (binfo->name, buf, rep->nameLength);
buf += _fs_pad_length (rep->nameLength);
}
pi = (fsPropInfo *) buf;
buf += SIZEOF (fsPropInfo);
po = (fsPropOffset *) buf;
buf += pi->num_offsets * SIZEOF (fsPropOffset);
pd = (pointer) buf;
buf += pi->data_len;
if (conn->fsMajorVersion > 1)
{
memcpy (binfo->name, buf, rep->nameLength);
buf += _fs_pad_length (rep->nameLength);
}
#ifdef DEBUG
binfo->name[rep->nameLength] = '\0';
fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
#endif
err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
if (err != Successful)
{
binfo->status = FS_LFWI_FINISHED;
goto done;
}
binfo->namelen = rep->nameLength;
binfo->remaining = rep->nReplies;
binfo->status = FS_LFWI_REPLY;
_fs_unmark_block (conn, FS_COMPLETE_REPLY);
FD_CLR(conn->fs_fd, &_fs_fd_mask);
done:
_fs_done_read (conn, rep->length << 2);
return err;
}
static int
fs_start_list_with_info(pointer client, FontPathElementPtr fpe,
char *pattern, int len, int maxnames, pointer *pdata)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
FSBlockedListInfoPtr binfo;
fsListFontsWithXInfoReq req;
if (conn->blockState & FS_GIVE_UP)
return BadFontName;
blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
if (!blockrec)
return AllocError;
binfo = (FSBlockedListInfoPtr) blockrec->data;
bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
binfo->status = FS_LFWI_WAITING;
if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
{
_fs_pending_reply (conn);
return Suspended;
}
_fs_client_access (conn, client, FALSE);
_fs_client_resolution(conn);
req.reqType = FS_ListFontsWithXInfo;
req.pad = 0;
req.maxNames = maxnames;
req.nbytes = len;
req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
_fs_add_req_log(conn, FS_ListFontsWithXInfo);
(void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
(void) _fs_write_pad(conn, pattern, len);
blockrec->sequenceNumber = conn->current_seq;
#ifdef NCD
if (configData.ExtendedFontDiags) {
char buf[256];
memcpy(buf, pattern, MIN(256, len));
buf[MIN(256, len)] = '\0';
printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
buf, fpe->name);
}
#endif
_fs_prepare_for_reply (conn);
return Successful;
}
static int
fs_next_list_with_info(pointer client, FontPathElementPtr fpe,
char **namep, int *namelenp,
FontInfoPtr *pFontInfo, int *numFonts,
pointer private)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec;
FSBlockedListInfoPtr binfo;
int err;
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
break;
if (!blockrec)
{
return BadFontName;
}
binfo = (FSBlockedListInfoPtr) blockrec->data;
if (binfo->status == FS_LFWI_WAITING)
return Suspended;
*namep = binfo->name;
*namelenp = binfo->namelen;
*pFontInfo = &binfo->info;
*numFonts = binfo->remaining;
FD_SET(conn->fs_fd, &_fs_fd_mask);
if (fs_reply_ready (conn))
_fs_mark_block (conn, FS_COMPLETE_REPLY);
err = blockrec->errcode;
switch (binfo->status) {
case FS_LFWI_FINISHED:
_fs_remove_block_rec(conn, blockrec);
break;
case FS_LFWI_REPLY:
binfo->status = FS_LFWI_WAITING;
blockrec->errcode = StillWorking;
conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
_fs_mark_block (conn, FS_PENDING_REPLY);
break;
}
return err;
}
static void
fs_client_died(pointer client, FontPathElementPtr fpe)
{
FSFpePtr conn = (FSFpePtr) fpe->private;
FSBlockDataPtr blockrec,
depending;
FSClientPtr *prev, cur;
fsFreeACReq freeac;
for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
{
if (cur->client == client) {
freeac.reqType = FS_FreeAC;
freeac.pad = 0;
freeac.id = cur->acid;
freeac.length = sizeof (fsFreeACReq) >> 2;
_fs_add_req_log(conn, FS_FreeAC);
_fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
*prev = cur->next;
free (cur);
break;
}
}
for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
if (blockrec->client == client)
break;
if (!blockrec)
return;
if ((depending = blockrec->depending))
{
blockrec->client = depending->client;
blockrec->depending = depending->depending;
blockrec = depending;
}
fs_abort_blockrec(conn, blockrec);
}
static void
_fs_client_access (FSFpePtr conn, pointer client, Bool sync)
{
FSClientPtr *prev, cur;
fsCreateACReq crac;
fsSetAuthorizationReq setac;
char *authorizations;
int authlen;
Bool new_cur = FALSE;
char padding[4] = { 0, 0, 0, 0 };
#ifdef DEBUG
if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
{
fprintf (stderr, "Sending requests without a connection\n");
}
#endif
for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
{
if (cur->client == client)
{
if (prev != &conn->clients)
{
*prev = cur->next;
cur->next = conn->clients;
conn->clients = cur;
}
break;
}
}
if (!cur)
{
cur = malloc (sizeof (FSClientRec));
if (!cur)
return;
cur->client = client;
cur->next = conn->clients;
conn->clients = cur;
cur->acid = GetNewFontClientID ();
new_cur = TRUE;
}
if (new_cur || cur->auth_generation != client_auth_generation(client))
{
if (!new_cur)
{
fsFreeACReq freeac;
freeac.reqType = FS_FreeAC;
freeac.pad = 0;
freeac.id = cur->acid;
freeac.length = sizeof (fsFreeACReq) >> 2;
_fs_add_req_log(conn, FS_FreeAC);
_fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
}
crac.reqType = FS_CreateAC;
crac.num_auths = set_font_authorizations(&authorizations, &authlen,
client);
if (crac.num_auths == 0) {
authorizations = padding;
authlen = 4;
} else {
authlen = (authlen + 3) & ~0x3;
}
crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
crac.acid = cur->acid;
_fs_add_req_log(conn, FS_CreateAC);
_fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
_fs_write(conn, authorizations, authlen);
conn->curacid = 0;
cur->auth_generation = client_auth_generation(client);
}
if (conn->curacid != cur->acid)
{
setac.reqType = FS_SetAuthorization;
setac.pad = 0;
setac.length = sizeof (fsSetAuthorizationReq) >> 2;
setac.id = cur->acid;
_fs_add_req_log(conn, FS_SetAuthorization);
_fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
conn->curacid = cur->acid;
}
}
static int
_fs_check_connect (FSFpePtr conn)
{
int ret;
ret = _fs_poll_connect (conn->trans_conn, 0);
switch (ret) {
case FSIO_READY:
conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
FD_SET (conn->fs_fd, &_fs_fd_mask);
break;
case FSIO_BLOCK:
break;
}
return ret;
}
static fsConnSetup *
_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
{
int ret;
char *data;
int headlen;
int len;
fsConnSetup *setup;
fsConnSetupAccept *accept;
ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
if (ret != FSIO_READY)
{
*error = ret;
return 0;
}
setup = (fsConnSetup *) data;
if (setup->major_version > FS_PROTOCOL)
{
*error = FSIO_ERROR;
return 0;
}
headlen = (SIZEOF (fsConnSetup) +
(setup->alternate_len << 2) +
(setup->auth_len << 2));
if (setup->status != AuthSuccess)
{
len = headlen;
}
else
{
ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
if (ret != FSIO_READY)
{
*error = ret;
return 0;
}
setup = (fsConnSetup *) data;
accept = (fsConnSetupAccept *) (data + headlen);
len = headlen + (accept->length << 2);
}
ret = _fs_start_read (conn, len, &data);
if (ret != FSIO_READY)
{
*error = ret;
return 0;
}
*setup_len = len;
return (fsConnSetup *) data;
}
static int
_fs_send_conn_client_prefix (FSFpePtr conn)
{
fsConnClientPrefix req;
int endian;
int ret;
endian = 1;
if (*(char *) &endian)
req.byteOrder = 'l';
else
req.byteOrder = 'B';
req.major_version = FS_PROTOCOL;
req.minor_version = FS_PROTOCOL_MINOR;
req.num_auths = 0;
req.auth_len = 0;
ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
if (ret != FSIO_READY)
return FSIO_ERROR;
conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
return ret;
}
static int
_fs_recv_conn_setup (FSFpePtr conn)
{
int ret = FSIO_ERROR;
fsConnSetup *setup;
FSFpeAltPtr alts;
int i, alt_len;
int setup_len;
char *alt_save, *alt_names;
setup = _fs_get_conn_setup (conn, &ret, &setup_len);
if (!setup)
return ret;
conn->current_seq = 0;
conn->fsMajorVersion = setup->major_version;
if (conn->alternate == 0)
{
if (conn->alts)
{
free (conn->alts);
conn->alts = 0;
conn->numAlts = 0;
}
if (setup->num_alternates)
{
alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
(setup->alternate_len << 2));
if (alts)
{
alt_names = (char *) (setup + 1);
alt_save = (char *) (alts + setup->num_alternates);
for (i = 0; i < setup->num_alternates; i++)
{
alts[i].subset = alt_names[0];
alt_len = alt_names[1];
alts[i].name = alt_save;
memcpy (alt_save, alt_names + 2, alt_len);
alt_save[alt_len] = '\0';
alt_save += alt_len + 1;
alt_names += _fs_pad_length (alt_len + 2);
}
conn->numAlts = setup->num_alternates;
conn->alts = alts;
}
}
}
_fs_done_read (conn, setup_len);
if (setup->status != AuthSuccess)
return FSIO_ERROR;
return FSIO_READY;
}
static int
_fs_open_server (FSFpePtr conn)
{
int ret;
char *servername;
if (conn->alternate == 0)
servername = conn->servername;
else
servername = conn->alts[conn->alternate-1].name;
conn->trans_conn = _fs_connect (servername, &ret);
conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
return ret;
}
static char *
_fs_catalog_name (char *servername)
{
char *sp;
sp = strchr (servername, '/');
if (!sp)
return 0;
return strrchr (sp + 1, '/');
}
static int
_fs_send_init_packets (FSFpePtr conn)
{
fsSetResolutionReq srreq;
fsSetCataloguesReq screq;
int num_cats,
clen;
char *catalogues;
char *cat;
char len;
char *end;
int num_res;
FontResolutionPtr res;
#define CATALOGUE_SEP '+'
res = GetClientResolutions(&num_res);
if (num_res)
{
srreq.reqType = FS_SetResolution;
srreq.num_resolutions = num_res;
srreq.length = (SIZEOF(fsSetResolutionReq) +
(num_res * SIZEOF(fsResolution)) + 3) >> 2;
_fs_add_req_log(conn, FS_SetResolution);
if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
return FSIO_ERROR;
if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
return FSIO_ERROR;
}
catalogues = 0;
if (conn->alternate != 0)
catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
if (!catalogues)
catalogues = _fs_catalog_name (conn->servername);
if (!catalogues)
{
conn->has_catalogues = FALSE;
return FSIO_READY;
}
conn->has_catalogues = TRUE;
catalogues++;
cat = catalogues;
num_cats = 0;
clen = 0;
while (*cat)
{
num_cats++;
end = strchr(cat, CATALOGUE_SEP);
if (!end)
end = cat + strlen (cat);
clen += (end - cat) + 1;
cat = end;
}
screq.reqType = FS_SetCatalogues;
screq.num_catalogues = num_cats;
screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
_fs_add_req_log(conn, FS_SetCatalogues);
if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
return FSIO_ERROR;
while (*cat)
{
num_cats++;
end = strchr(cat, CATALOGUE_SEP);
if (!end)
end = cat + strlen (cat);
len = end - cat;
if (_fs_write (conn, &len, 1) != FSIO_READY)
return FSIO_ERROR;
if (_fs_write (conn, cat, (int) len) != FSIO_READY)
return FSIO_ERROR;
cat = end;
}
if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
return FSIO_ERROR;
return FSIO_READY;
}
static int
_fs_send_cat_sync (FSFpePtr conn)
{
fsListCataloguesReq lcreq;
lcreq.reqType = FS_ListCatalogues;
lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
lcreq.maxNames = 0;
lcreq.nbytes = 0;
lcreq.pad2 = 0;
_fs_add_req_log(conn, FS_SetCatalogues);
if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
return FSIO_ERROR;
conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
return FSIO_READY;
}
static int
_fs_recv_cat_sync (FSFpePtr conn)
{
fsGenericReply *reply;
fsError *error;
int err;
int ret;
reply = fs_get_reply (conn, &err);
if (!reply)
return err;
ret = FSIO_READY;
if (reply->type == FS_Error)
{
error = (fsError *) reply;
if (error->major_opcode == FS_SetCatalogues)
ret = FSIO_ERROR;
}
_fs_done_read (conn, reply->length << 2);
return ret;
}
static void
_fs_close_server (FSFpePtr conn)
{
_fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
if (conn->trans_conn)
{
_FontTransClose (conn->trans_conn);
conn->trans_conn = 0;
_fs_io_reinit (conn);
}
if (conn->fs_fd >= 0)
{
FD_CLR (conn->fs_fd, &_fs_fd_mask);
conn->fs_fd = -1;
}
conn->fs_conn_state = FS_CONN_UNCONNECTED;
}
static int
_fs_do_setup_connection (FSFpePtr conn)
{
int ret;
do
{
#ifdef DEBUG
fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
#endif
switch (conn->fs_conn_state) {
case FS_CONN_UNCONNECTED:
ret = _fs_open_server (conn);
if (ret == FSIO_BLOCK)
conn->fs_conn_state = FS_CONN_CONNECTING;
break;
case FS_CONN_CONNECTING:
ret = _fs_check_connect (conn);
break;
case FS_CONN_CONNECTED:
ret = _fs_send_conn_client_prefix (conn);
break;
case FS_CONN_SENT_PREFIX:
ret = _fs_recv_conn_setup (conn);
break;
case FS_CONN_RECV_INIT:
ret = _fs_send_init_packets (conn);
if (conn->has_catalogues)
ret = _fs_send_cat_sync (conn);
break;
case FS_CONN_SENT_CAT:
if (conn->has_catalogues)
ret = _fs_recv_cat_sync (conn);
else
ret = FSIO_READY;
break;
default:
ret = FSIO_READY;
break;
}
switch (ret) {
case FSIO_READY:
if (conn->fs_conn_state < FS_CONN_RUNNING)
conn->fs_conn_state++;
break;
case FSIO_BLOCK:
if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
break;
ret = FSIO_ERROR;
case FSIO_ERROR:
_fs_close_server (conn);
if (conn->alternate < conn->numAlts)
{
conn->alternate++;
ret = FSIO_READY;
}
else
conn->alternate = 0;
break;
}
} while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
if (ret == FSIO_READY)
conn->generation = ++generationCount;
return ret;
}
static int
_fs_wait_connect (FSFpePtr conn)
{
int ret;
for (;;)
{
ret = _fs_do_setup_connection (conn);
if (ret != FSIO_BLOCK)
break;
if (conn->fs_conn_state <= FS_CONN_CONNECTING)
ret = _fs_poll_connect (conn->trans_conn, 1000);
else
ret = _fs_wait_for_readable (conn, 1000);
if (ret == FSIO_ERROR)
break;
}
return ret;
}
static void
_fs_check_reconnect (FSFpePtr conn)
{
int ret;
ret = _fs_do_setup_connection (conn);
switch (ret) {
case FSIO_READY:
_fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
_fs_restart_connection (conn);
break;
case FSIO_BLOCK:
break;
case FSIO_ERROR:
conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
break;
}
}
static void
_fs_start_reconnect (FSFpePtr conn)
{
if (conn->blockState & FS_RECONNECTING)
return;
conn->alternate = 0;
_fs_mark_block (conn, FS_RECONNECTING);
_fs_unmark_block (conn, FS_BROKEN_CONNECTION);
_fs_check_reconnect (conn);
}
static FSFpePtr
_fs_init_conn (char *servername)
{
FSFpePtr conn;
conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
if (!conn)
return 0;
if (!_fs_io_init (conn))
{
free (conn);
return 0;
}
conn->servername = (char *) (conn + 1);
conn->fs_conn_state = FS_CONN_UNCONNECTED;
conn->fs_fd = -1;
strcpy (conn->servername, servername);
return conn;
}
static void
_fs_free_conn (FSFpePtr conn)
{
_fs_close_server (conn);
_fs_io_fini (conn);
if (conn->alts)
free (conn->alts);
free (conn);
}
void
fs_register_fpe_functions(void)
{
RegisterFPEFunctions(fs_name_check,
fs_init_fpe,
fs_free_fpe,
fs_reset_fpe,
fs_open_font,
fs_close_font,
fs_list_fonts,
fs_start_list_with_info,
fs_next_list_with_info,
fs_wakeup,
fs_client_died,
_fs_load_glyphs,
NULL,
NULL,
NULL);
}