/**************************************************************************/
/*                                                                        */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)          */
/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>  */
/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de>                */
/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de>                 */
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com)           */
/*                                                                        */
/* NXAGENT, NX protocol compression and NX extensions to this software    */
/* are copyright of the aforementioned persons and companies.             */
/*                                                                        */
/* Redistribution and use of the present software is allowed according    */
/* to terms specified in the file LICENSE which comes in the source       */
/* distribution.                                                          */
/*                                                                        */
/* All rights reserved.                                                   */
/*                                                                        */
/* NOTE: This software has received contributions from various other      */
/* contributors, only the core maintainers and supporters are listed as   */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well.                                          */
/*                                                                        */
/**************************************************************************/

/************************************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

************************************************************************/
/* The panoramix components contained the following notice */
/*
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of Digital Equipment Corporation
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from Digital
Equipment Corporation.

******************************************************************/

#include "dixstruct.h"
#include "dixfontstr.h"

static Bool doOpenFont(ClientPtr client, OFclosurePtr c);
static Bool doListFontsAndAliases(ClientPtr client, LFclosurePtr c);

#include "../../dix/dixfonts.c"

#include "Agent.h"
#include "Font.h"

#ifdef NXAGENT_SERVER

#define PANIC
#define WARNING
#undef  TEST
#undef  DEBUG

/* This enables code that contains copies of code from libXfont.
 * We copy+pasted the private _LFWIData type struct into this
 * file. If this gets ever changed in libXfont, we must follow-up
 * on that change here, too.
 */
#define NXAGENT_DANGEROUS_XFONT_LOOP_EXIT

#define NXFONTPATHLENGTH 1024
char _NXFontPath[NXFONTPATHLENGTH];

/*
 * Override the default font path and make
 * it configurable at run time, based on
 * the NX_FONT environment.
 */

static char *_NXGetFontPath(const char *path)
{
    /*
     * Check the environment only once.
     */

    if (_NXFontPath[0] != '\0')
    {
        return _NXFontPath;
    }

    const char *fontEnv = getenv("NX_FONT");

    if (fontEnv != NULL && *fontEnv != '\0')
    {
        if (strlen(fontEnv) + 1 > NXFONTPATHLENGTH)
        {
            #ifdef TEST
            fprintf(stderr, "_NXGetFontPath: WARNING! Maximum length of font path exceeded.\n");
            #endif
            goto _NXGetFontPathError;
        }

        snprintf(_NXFontPath, NXFONTPATHLENGTH, "%s", fontEnv);

        #ifdef TEST
        fprintf(stderr, "_NXGetFontPath: Using NX font path [%s].\n", _NXFontPath);
        #endif

        return _NXFontPath;
    }

_NXGetFontPathError:

    snprintf(_NXFontPath, NXFONTPATHLENGTH, "%s", path);

    #ifdef TEST
    fprintf(stderr, "_NXGetFontPath: Using default font path [%s].\n", _NXFontPath);
    #endif

    return _NXFontPath;
}

#endif

static Bool
doOpenFont(ClientPtr client, OFclosurePtr c)
{
    FontPtr     pfont = NullFont;
    FontPathElementPtr fpe = NULL;
    ScreenPtr   pScr;
    int         err = Successful;
    int         i;
    char       *alias,
               *newname;
    int         newlen;
    int		aliascount = 20;
#ifdef NXAGENT_SERVER
    char nxagentOrigFontName[256];
    int nxagentOrigFontNameLen;
#endif

    /*
     * Decide at runtime what FontFormat to use.
     */
    Mask FontFormat = 

	((screenInfo.imageByteOrder == LSBFirst) ?
	    BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |

	((screenInfo.bitmapBitOrder == LSBFirst) ?
	    BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |

	BitmapFormatImageRectMin |

#if GLYPHPADBYTES == 1
	BitmapFormatScanlinePad8 |
#endif

#if GLYPHPADBYTES == 2
	BitmapFormatScanlinePad16 |
#endif

#if GLYPHPADBYTES == 4
	BitmapFormatScanlinePad32 |
#endif

#if GLYPHPADBYTES == 8
	BitmapFormatScanlinePad64 |
#endif

	BitmapFormatScanlineUnit8;

#ifdef NXAGENT_SERVER
    nxagentOrigFontNameLen = (c -> origFontNameLen < sizeof(nxagentOrigFontName) ? c -> origFontNameLen : sizeof(nxagentOrigFontName) - 1);

    memcpy(nxagentOrigFontName, c -> origFontName, nxagentOrigFontNameLen);

    nxagentOrigFontName[nxagentOrigFontNameLen] = 0;
#endif
    if (client->clientGone)
    {
	if (c->current_fpe < c->num_fpes)
	{
	    fpe = c->fpe_list[c->current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }
    while (c->current_fpe < c->num_fpes) {
	fpe = c->fpe_list[c->current_fpe];
#ifdef HAS_XFONT2
	err = (*fpe_functions[fpe->type]->open_font)
#else
	err = (*fpe_functions[fpe->type].open_font)
#endif /* HAS_XFONT2 */
	    ((void *) client, fpe, c->flags,
	     c->fontname, c->fnamelen, FontFormat,
	     BitmapFormatMaskByte |
	     BitmapFormatMaskBit |
	     BitmapFormatMaskImageRectangle |
	     BitmapFormatMaskScanLinePad |
	     BitmapFormatMaskScanLineUnit,
	     c->fontid, &pfont, &alias,
	     c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
		 c->non_cachable_font :
		 (FontPtr)0);

	if (err == FontNameAlias && alias) {
	    newlen = strlen(alias);
	    newname = (char *) realloc(c->fontname, newlen);
	    if (!newname) {
		err = AllocError;
		break;
	    }
	    memmove(newname, alias, newlen);
	    c->fontname = newname;
	    c->fnamelen = newlen;
	    c->current_fpe = 0;
	    if (--aliascount <= 0)
		break;
	    continue;
	}
	if (err == BadFontName) {
	    c->current_fpe++;
	    continue;
	}
	if (err == Suspended) {
	    if (!c->slept) {
		c->slept = TRUE;
		ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (void *) c);
#ifdef NXAGENT_SERVER
                #ifdef DEBUG
                fprintf(stderr, " NXdixfonts: doOpenFont: client [%lx] sleeping.\n", client);
                #endif
#endif
	    }
	    return TRUE;
	}
	break;
    }

    if (err != Successful)
	goto bail;
    if (!pfont) {
	err = BadFontName;
	goto bail;
    }
    /* check values for firstCol, lastCol, firstRow, and lastRow */
    if (pfont->info.firstCol > pfont->info.lastCol ||
       pfont->info.firstRow > pfont->info.lastRow ||
       pfont->info.lastCol - pfont->info.firstCol > 255) {
       err = AllocError;
       goto bail;
    }
    if (!pfont->fpe)
	pfont->fpe = fpe;
    pfont->refcnt++;
    if (pfont->refcnt == 1) {
	UseFPE(pfont->fpe);
	for (i = 0; i < screenInfo.numScreens; i++) {
	    pScr = screenInfo.screens[i];
	    if (pScr->RealizeFont)
	    {
#ifdef NXAGENT_SERVER
                /*
                 * NXAGENT uses useless screen pointer to pass the original font name
                 * to realizeFont, could be a source of problems in the future.
                 */

		if (!(*pScr->RealizeFont) ((ScreenPtr)nxagentOrigFontName, pfont))
#else
		if (!(*pScr->RealizeFont) (pScr, pfont))
#endif
		{
		    CloseFont (pfont, (Font) 0);
#ifdef NXAGENT_SERVER
		    err = BadFontName;
#else
		    err = AllocError;
#endif
		    goto bail;
		}
	    }
	}
    }
    if (!AddResource(c->fontid, RT_FONT, (void *) pfont)) {
	err = AllocError;
	goto bail;
    }
#ifdef NXAGENT_SERVER
    if( nxagentFontPriv(pfont) -> mirrorID == 0 )
    {
      extern RESTYPE RT_NX_FONT;

      nxagentFontPriv(pfont) -> mirrorID = FakeClientID(0);
      if (!AddResource(nxagentFontPriv(pfont) -> mirrorID, RT_NX_FONT, (void *) pfont)) {
        FreeResource(c->fontid, RT_NONE);
        err = AllocError;
        goto bail;
      }
    }
#endif
    if (patternCache && pfont != c->non_cachable_font)
#ifdef NXAGENT_SERVER
  #ifdef HAS_XFONT2
	xfont2_cache_font_pattern(patternCache, nxagentOrigFontName, nxagentOrigFontNameLen,
  #else
	CacheFontPattern(patternCache, nxagentOrigFontName, nxagentOrigFontNameLen,
  #endif /* HAS_XFONT2 */
#else
  #ifdef HAS_XFONT2
	xfont2_cache_font_pattern(patternCache, c->origFontName, c->origFontNameLen,
  #else
	CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
  #endif /* HAS_XFONT2 */
#endif
			 pfont);
bail:
    if (err != Successful && c->client != serverClient) {
	SendErrorToClient(c->client, X_OpenFont, 0,
			  c->fontid, FontToXError(err));
    }
    if (c->slept)
#ifdef NXAGENT_SERVER
    {
	ClientWakeup(c->client);
        #ifdef DEBUG
        fprintf(stderr, " NXdixfonts: doOpenFont: client [%lx] wakeup.\n", client);
        #endif
    }
#else
	ClientWakeup(c->client);
#endif
    for (i = 0; i < c->num_fpes; i++) {
	FreeFPE(c->fpe_list[i]);
    }
    free(c->fpe_list);
    free(c->fontname);
    free(c);
    return TRUE;
}


static Bool
doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
{
    FontPathElementPtr fpe;
    int         err = Successful;
    FontNamesPtr names = NULL;
    char       *name, *resolved=NULL;
    int         namelen, resolvedlen;
    int		nnames;
    int         stringLens;
    int         i;
    xListFontsReply reply;
    char	*bufptr;
    char	*bufferStart;
    int		aliascount = 0;

    if (client->clientGone)
    {
	if (c->current.current_fpe < c->num_fpes)
	{
	    fpe = c->fpe_list[c->current.current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }

    if (!c->current.patlen)
	goto finish;

    while (c->current.current_fpe < c->num_fpes) {
	fpe = c->fpe_list[c->current.current_fpe];
	err = Successful;

#ifdef HAS_XFONT2
	if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
	{
	    /* This FPE doesn't support/require list_fonts_and_aliases */

#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->list_fonts)
#else
	    err = (*fpe_functions[fpe->type].list_fonts)
#endif /* HAS_XFONT2 */
		((void *) c->client, fpe, c->current.pattern,
		 c->current.patlen, c->current.max_names - c->names->nnames,
		 c->names);

	    if (err == Suspended) {
		if (!c->slept) {
		    c->slept = TRUE;
		    ClientSleep(client,
			(ClientSleepProcPtr)doListFontsAndAliases,
			(void *) c);
#ifdef NXAGENT_SERVER
                    #ifdef DEBUG
                    fprintf(stderr, " NXdixfonts: doListFont (1): client [%lx] sleeping.\n", client);
                    #endif
#endif
		}
		return TRUE;
	    }

	    err = BadFontName;
	}
	else
	{
	    /* Start of list_fonts_and_aliases functionality.  Modeled
	       after list_fonts_with_info in that it resolves aliases,
	       except that the information collected from FPEs is just
	       names, not font info.  Each list_next_font_or_alias()
	       returns either a name into name/namelen or an alias into
	       name/namelen and its target name into resolved/resolvedlen.
	       The code at this level then resolves the alias by polling
	       the FPEs.  */

	    if (!c->current.list_started) {
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, c->current.pattern,
		     c->current.patlen, c->current.max_names - c->names->nnames,
		     &c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)doListFontsAndAliases,
				    (void *) c);
			c->slept = TRUE;
#ifdef NXAGENT_SERVER
                        #ifdef DEBUG
                        fprintf(stderr, " NXdixfonts: doListFont (2): client [%lx] sleeping.\n", client);
                        #endif
#endif
		    }
		    return TRUE;
		}
		if (err == Successful)
		    c->current.list_started = TRUE;
	    }
	    if (err == Successful) {
		char    *tmpname;
		name = 0;
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, &name, &namelen, &tmpname,
		     &resolvedlen, c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)doListFontsAndAliases,
				    (void *) c);
			c->slept = TRUE;
#ifdef NXAGENT_SERVER
                        #ifdef DEBUG
                        fprintf(stderr, " NXdixfonts: doListFont (3): client [%lx] sleeping.\n", client);
                        #endif
#endif
		    }
		    return TRUE;
		}
		if (err == FontNameAlias) {
		    free(resolved);
		    resolved = (char *) malloc(resolvedlen + 1);
		    if (resolved)
			memmove(resolved, tmpname, resolvedlen + 1);
		}
	    }

	    if (err == Successful)
	    {
		if (c->haveSaved)
		{
		    if (c->savedName)
#ifdef HAS_XFONT2
			(void)xfont2_add_font_names_name(c->names, c->savedName,
#else
			(void)AddFontNamesName(c->names, c->savedName,
#endif /* HAS_XFONT2 */
					       c->savedNameLen);
		}
		else
#ifdef HAS_XFONT2
		    (void)xfont2_add_font_names_name(c->names, name, namelen);
#else
		    (void)AddFontNamesName(c->names, name, namelen);
#endif /* HAS_XFONT2 */
	    }

	    /*
	     * When we get an alias back, save our state and reset back to
	     * the start of the FPE looking for the specified name.  As
	     * soon as a real font is found for the alias, pop back to the
	     * old state
	     */
	    else if (err == FontNameAlias) {
		char	tmp_pattern[XLFDMAXFONTNAMELEN];
		/*
		 * when an alias recurses, we need to give
		 * the last FPE a chance to clean up; so we call
		 * it again, and assume that the error returned
		 * is BadFontName, indicating the alias resolution
		 * is complete.
		 */
		memmove(tmp_pattern, resolved, resolvedlen);
		if (c->haveSaved)
		{
		    char    *tmpname;
		    int     tmpnamelen;

		    tmpname = 0;
#ifdef HAS_XFONT2
		    (void) (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
			((void *) c->client, fpe, &tmpname, &tmpnamelen,
			 &tmpname, &tmpnamelen, c->current.private);
		    if (--aliascount <= 0)
		    {
			err = BadFontName;
			goto ContBadFontName;
		    }
		}
		else
		{
		    c->saved = c->current;
		    c->haveSaved = TRUE;
		    free(c->savedName);
		    c->savedName = (char *)malloc(namelen + 1);
		    if (c->savedName)
			memmove(c->savedName, name, namelen + 1);
		    c->savedNameLen = namelen;
		    aliascount = 20;
		}
		memmove(c->current.pattern, tmp_pattern, resolvedlen);
		c->current.patlen = resolvedlen;
		c->current.max_names = c->names->nnames + 1;
		c->current.current_fpe = -1;
		c->current.private = 0;
		err = BadFontName;
	    }
	}
	/*
	 * At the end of this FPE, step to the next.  If we've finished
	 * processing an alias, pop state back. If we've collected enough
	 * font names, quit.
	 */
	if (err == BadFontName) {
	  ContBadFontName: ;
	    c->current.list_started = FALSE;
	    c->current.current_fpe++;
	    err = Successful;
	    if (c->haveSaved)
	    {
		if (c->names->nnames == c->current.max_names ||
			c->current.current_fpe == c->num_fpes) {
		    c->haveSaved = FALSE;
		    c->current = c->saved;
		    /* Give the saved namelist a chance to clean itself up */
		    continue;
		}
	    }
	    if (c->names->nnames == c->current.max_names)
		break;
	}
    }

    /*
     * send the reply
     */
    if (err != Successful) {
	SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
	goto bail;
    }

finish:

    names = c->names;
    nnames = names->nnames;
    client = c->client;
    stringLens = 0;
    for (i = 0; i < nnames; i++)
	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;

    memset(&reply, 0, sizeof(xListFontsReply));
    reply.type = X_Reply;
    reply.length = (stringLens + nnames + 3) >> 2;
    reply.nFonts = nnames;
    reply.sequenceNumber = client->sequence;

#ifdef NXAGENT_SERVER
    bufptr = bufferStart = (char *) calloc(1, reply.length << 2);
#else
    bufptr = bufferStart = (char *) malloc(reply.length << 2);
#endif
    if (!bufptr && reply.length) {
	SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
	goto bail;
    }
    /*
     * since WriteToClient long word aligns things, copy to temp buffer and
     * write all at once
     */
    for (i = 0; i < nnames; i++) {
	if (names->length[i] > 255)
	    reply.nFonts--;
	else
	{
#ifdef NXAGENT_SERVER
	    {
	        /* dirty hack: don't list to client fonts not existing on the remote side */
	        char tmp[256];

	        memcpy(tmp, names->names[i], names->length[i]);
	        tmp[ names->length[i] ] = 0;

	        if (nxagentFontLookUp(tmp) == 0)
	        {
#ifdef NXAGENT_FONTMATCH_DEBUG
		    fprintf(stderr, "doListFontsAndAliases:\n");
		    fprintf(stderr, "      removing font: %s \n", tmp);
#endif
		    reply.nFonts--;
		    stringLens -= names->length[i];
		    continue;
	        }
	    }
#endif
	    *bufptr++ = names->length[i];
	    memmove( bufptr, names->names[i], names->length[i]);
	    bufptr += names->length[i];
	}
    }
    nnames = reply.nFonts;
    reply.length = (stringLens + nnames + 3) >> 2;
    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
    WriteToClient(client, stringLens + nnames, bufferStart);
    free(bufferStart);

bail:
    if (c->slept)
    {
        ClientWakeup(client);
#ifdef NXAGENT_SERVER
        #ifdef DEBUG
        fprintf(stderr, " NXdixfonts: doListFont: client [%lx] wakeup.\n", client);
        #endif
#endif
    }
    for (i = 0; i < c->num_fpes; i++)
	FreeFPE(c->fpe_list[i]);
    free(c->fpe_list);
    free(c->savedName);
#ifdef HAS_XFONT2
    xfont2_free_font_names(names);
#else
    FreeFontNames(names);
#endif /* HAS_XFONT2 */
    free(c);
    free(resolved);
    return TRUE;
}

int
ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, 
          unsigned max_names)
{
    int         i;
    LFclosurePtr c;

    /* 
     * The right error to return here would be BadName, however the
     * specification does not allow for a Name error on this request.
     * Perhaps a better solution would be to return a nil list, i.e.
     * a list containing zero fontnames.
     */
    if (length > XLFDMAXFONTNAMELEN)
	return BadAlloc;

    if (!(c = (LFclosurePtr) calloc(1, sizeof *c)))
	return BadAlloc;
    c->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!c->fpe_list) {
	free(c);
	return BadAlloc;
    }
#ifdef NXAGENT_SERVER
  #ifdef HAS_XFONT2
    c->names = xfont2_make_font_names_record(max_names < nxagentMaxFontNames ? max_names : nxagentMaxFontNames);
  #else
    c->names = MakeFontNamesRecord(max_names < nxagentMaxFontNames ? max_names : nxagentMaxFontNames);
  #endif /* HAS_XFONT2 */
#else
  #ifdef HAS_XFONT2
    c->names = xfont2_make_font_names_record(max_names < 100 ? max_names : 100);
  #else
    c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
  #endif /* HAS_XFONT2 */
#endif
    if (!c->names)
    {
	free(c->fpe_list);
	free(c);
	return BadAlloc;
    }
    memmove( c->current.pattern, pattern, length);
    for (i = 0; i < num_fpes; i++) {
	c->fpe_list[i] = font_path_elements[i];
	UseFPE(c->fpe_list[i]);
    }
    c->client = client;
    c->num_fpes = num_fpes;
    c->current.patlen = length;
    c->current.current_fpe = 0;
    c->current.max_names = max_names;
    c->current.list_started = FALSE;
    c->current.private = 0;
    c->haveSaved = FALSE;
    c->slept = FALSE;
    c->savedName = 0;
    doListFontsAndAliases(client, c);
    return Success;
}

int
doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
{
    FontPathElementPtr fpe;
    int         err = Successful;
    char       *name;
    int         namelen;
    int         numFonts;
    FontInfoRec fontInfo,
               *pFontInfo;
    xListFontsWithInfoReply *reply;
    int         length;
    xFontProp  *pFP;
    int         i;
    int		aliascount = 0;
    xListFontsWithInfoReply finalReply;

    if (client->clientGone)
    {
	if (c->current.current_fpe < c->num_fpes)
 	{
	    fpe = c->fpe_list[c->current.current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }
    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
    if (!c->current.patlen)
	goto finish;
    while (c->current.current_fpe < c->num_fpes)
    {
	fpe = c->fpe_list[c->current.current_fpe];
	err = Successful;
	if (!c->current.list_started)
 	{
#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->start_list_fonts_with_info)
#else
	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
#endif /* HAS_XFONT2 */
		(client, fpe, c->current.pattern, c->current.patlen,
		 c->current.max_names, &c->current.private);
	    if (err == Suspended)
 	    {
		if (!c->slept)
 		{
		    ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c);
		    c->slept = TRUE;
#ifdef NXAGENT_SERVER
                    #ifdef DEBUG
                    fprintf(stderr, " NXdixfonts: doListFontWinfo (1): client [%lx] sleeping.\n", client);
                    #endif
#endif
		}
		return TRUE;
	    }
	    if (err == Successful)
		c->current.list_started = TRUE;
	}
	if (err == Successful)
 	{
	    name = 0;
	    pFontInfo = &fontInfo;
#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->list_next_font_with_info)
#else
	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
#endif /* HAS_XFONT2 */
		(client, fpe, &name, &namelen, &pFontInfo,
		 &numFonts, c->current.private);
	    if (err == Suspended)
 	    {
		if (!c->slept)
 		{
		    ClientSleep(client,
		    	     (ClientSleepProcPtr)doListFontsWithInfo,
			     c);
		    c->slept = TRUE;
#ifdef NXAGENT_SERVER
                    #ifdef DEBUG
                    fprintf(stderr, " NXdixfonts: doListFontWinfo (2): client [%lx] sleeping.\n", client);
                    #endif
#endif
		}
		return TRUE;
	    }
	}
	/*
	 * When we get an alias back, save our state and reset back to the
	 * start of the FPE looking for the specified name.  As soon as a real
	 * font is found for the alias, pop back to the old state
	 */
	if (err == FontNameAlias)
 	{
	    /*
	     * when an alias recurses, we need to give
	     * the last FPE a chance to clean up; so we call
	     * it again, and assume that the error returned
	     * is BadFontName, indicating the alias resolution
	     * is complete.
	     */
	    if (c->haveSaved)
	    {
		char	*tmpname;
		int	tmpnamelen;
		FontInfoPtr tmpFontInfo;

	    	tmpname = 0;
	    	tmpFontInfo = &fontInfo;
#ifdef HAS_XFONT2
		(void) (*fpe_functions[fpe->type]->list_next_font_with_info)
#else
		(void) (*fpe_functions[fpe->type].list_next_font_with_info)
#endif /* HAS_XFONT2 */
		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
		     &numFonts, c->current.private);
		if (--aliascount <= 0)
		{
		    err = BadFontName;
		    goto ContBadFontName;
		}
	    }
	    else
	    {
		c->saved = c->current;
		c->haveSaved = TRUE;
		c->savedNumFonts = numFonts;
		free(c->savedName);
		c->savedName = (char *)malloc(namelen + 1);
		if (c->savedName)
		  memmove(c->savedName, name, namelen + 1);
		aliascount = 20;
	    }
	    memmove(c->current.pattern, name, namelen);
	    c->current.patlen = namelen;
	    c->current.max_names = 1;
	    c->current.current_fpe = 0;
	    c->current.private = 0;
	    c->current.list_started = FALSE;
	}
	/*
	 * At the end of this FPE, step to the next.  If we've finished
	 * processing an alias, pop state back.  If we've sent enough font
	 * names, quit.  Always wait for BadFontName to let the FPE
	 * have a chance to clean up.
	 */
	else if (err == BadFontName)
 	{
	  ContBadFontName: ;
	    c->current.list_started = FALSE;
	    c->current.current_fpe++;
#ifdef NXAGENT_SERVER
	    c->current.private = 0;   /* BadFontName -> private has been freed */
#endif
	    err = Successful;
	    if (c->haveSaved)
 	    {
		if (c->current.max_names == 0 ||
			c->current.current_fpe == c->num_fpes)
 		{
		    c->haveSaved = FALSE;
		    c->saved.max_names -= (1 - c->current.max_names);
		    c->current = c->saved;
		}
	    }
	    else if (c->current.max_names == 0)
		break;
	}
 	else if (err == Successful)
 	{
#ifdef NXAGENT_SERVER
	    if (c->haveSaved)
 	    {
	        numFonts = c->savedNumFonts;
	        name = c->savedName;
	        namelen = strlen(name);
	    }

	    if (nxagentFontLookUp(name) == 0)
	    {
#ifdef NXAGENT_FONTMATCH_DEBUG
	        fprintf(stderr, "doListFontsAndAliases (with info):\n");
	        fprintf(stderr, "      removing font: %s \n", name);
#endif
	        continue;
            }
#endif
	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
	    reply = c->reply;
	    if (c->length < length)
 	    {
		reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
		if (!reply)
 		{
		    err = AllocError;
		    break;
		}
		memset(reply + c->length, 0, length - c->length);
		c->reply = reply;
		c->length = length;
	    }
#ifndef NXAGENT_SERVER
	    if (c->haveSaved)
	    {
		numFonts = c->savedNumFonts;
		name = c->savedName;
		namelen = strlen(name);
	    }
#endif
	    reply->type = X_Reply;
	    reply->length = (sizeof *reply - sizeof(xGenericReply) +
			     pFontInfo->nprops * sizeof(xFontProp) +
			     namelen + 3) >> 2;
	    reply->sequenceNumber = client->sequence;
	    reply->nameLength = namelen;
	    reply->minBounds = pFontInfo->ink_minbounds;
	    reply->maxBounds = pFontInfo->ink_maxbounds;
	    reply->minCharOrByte2 = pFontInfo->firstCol;
	    reply->maxCharOrByte2 = pFontInfo->lastCol;
	    reply->defaultChar = pFontInfo->defaultCh;
	    reply->nFontProps = pFontInfo->nprops;
	    reply->drawDirection = pFontInfo->drawDirection;
	    reply->minByte1 = pFontInfo->firstRow;
	    reply->maxByte1 = pFontInfo->lastRow;
	    reply->allCharsExist = pFontInfo->allExist;
	    reply->fontAscent = pFontInfo->fontAscent;
	    reply->fontDescent = pFontInfo->fontDescent;
	    reply->nReplies = numFonts;
	    pFP = (xFontProp *) (reply + 1);
	    for (i = 0; i < pFontInfo->nprops; i++)
 	    {
		pFP->name = pFontInfo->props[i].name;
		pFP->value = pFontInfo->props[i].value;
		pFP++;
	    }
	    WriteSwappedDataToClient(client, length, reply);
	    WriteToClient(client, namelen, name);
	    if (pFontInfo == &fontInfo)
 	    {
		free(fontInfo.props);
		free(fontInfo.isStringProp);
	    }
	    --c->current.max_names;
	}
    }
finish:
    length = sizeof(xListFontsWithInfoReply);
    bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
    finalReply.type = X_Reply;
    finalReply.sequenceNumber = client->sequence;
    finalReply.length = (sizeof(xListFontsWithInfoReply)
		     - sizeof(xGenericReply)) >> 2;
    WriteSwappedDataToClient(client, length, &finalReply);
bail:
    if (c->slept)
#ifdef NXAGENT_SERVER
    {
	ClientWakeup(client);
        #ifdef DEBUG
        fprintf(stderr, " NXdixfonts: doListFontWinfo: client [%lx] wakeup.\n", client);
        #endif
    }
#else
	ClientWakeup(client);
#endif
    for (i = 0; i < c->num_fpes; i++)
	FreeFPE(c->fpe_list[i]);
    free(c->reply);
    free(c->fpe_list);
    free(c->savedName);
    free(c);
    return TRUE;
}


int
SetDefaultFontPath(char *path)
{
    return xorg_SetDefaultFontPath(_NXGetFontPath(path));
}

typedef struct
{
   LFclosurePtr c;
   OFclosurePtr oc;
} nxFs,*nxFsPtr;

/* this is derived from doListFontsAndAliases above */
static Bool
nxdoListFontsAndAliases(ClientPtr client, nxFsPtr fss)
{
    LFclosurePtr c = fss->c;
    OFclosurePtr oc = fss->oc;
    FontPathElementPtr fpe;
    int         err = Successful;
    char       *name, *resolved=NULL;
    int         namelen, resolvedlen;
    int         i;
    int		aliascount = 0;
    char        tmp[256];

    tmp[0] = 0;
    if (client->clientGone)
    {
	if (c->current.current_fpe < c->num_fpes)
	{
	    fpe = c->fpe_list[c->current.current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }

    if (!c->current.patlen)
	goto finish;

    while (c->current.current_fpe < c->num_fpes) {
	fpe = c->fpe_list[c->current.current_fpe];
	err = Successful;

#ifdef HAS_XFONT2
	if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
	{
	    /* This FPE doesn't support/require list_fonts_and_aliases */

#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->list_fonts)
#else
	    err = (*fpe_functions[fpe->type].list_fonts)
#endif /* HAS_XFONT2 */
		((void *) c->client, fpe, c->current.pattern,
		 c->current.patlen, c->current.max_names - c->names->nnames,
		 c->names);

	    if (err == Suspended) {
		if (!c->slept) {
		    c->slept = TRUE;
		    ClientSleep(client,
			(ClientSleepProcPtr)nxdoListFontsAndAliases,
			(void *) fss);
                    #ifdef DEBUG
                    fprintf(stderr, " NXdixfonts: nxdoListFont (1): client [%lx] sleeping.\n", client);
                    #endif
		}
		return TRUE;
	    }

	    err = BadFontName;
	}
	else
	{
	    /* Start of list_fonts_and_aliases functionality.  Modeled
	       after list_fonts_with_info in that it resolves aliases,
	       except that the information collected from FPEs is just
	       names, not font info.  Each list_next_font_or_alias()
	       returns either a name into name/namelen or an alias into
	       name/namelen and its target name into resolved/resolvedlen.
	       The code at this level then resolves the alias by polling
	       the FPEs.  */

	    if (!c->current.list_started) {
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, c->current.pattern,
		     c->current.patlen, c->current.max_names - c->names->nnames,
		     &c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)nxdoListFontsAndAliases,
				    (void *) fss);
			c->slept = TRUE;
                        #ifdef DEBUG
                        fprintf(stderr, " NXdixfonts: nxdoListFont (2): client [%lx] sleeping.\n", client);
                        #endif
		    }
		    return TRUE;
		}
		if (err == Successful)
		    c->current.list_started = TRUE;
	    }
	    if (err == Successful) {
		char    *tmpname;
		name = 0;
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, &name, &namelen, &tmpname,
		     &resolvedlen, c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)nxdoListFontsAndAliases,
				    (void *) fss);
			c->slept = TRUE;
                        #ifdef DEBUG
                        fprintf(stderr, " NXdixfonts: nxdoListFont (3): client [%lx] sleeping.\n", client);
                        #endif
		    }
		    return TRUE;
		}
		if (err == FontNameAlias) {
		    free(resolved);
		    resolved = (char *) malloc(resolvedlen + 1);
		    if (resolved)
                    {
                        memmove(resolved, tmpname, resolvedlen);
                        resolved[resolvedlen] = '\0';
                    }
		}
	    }

	    if (err == Successful)
	    {
#ifndef NXAGENT_DANGEROUS_XFONT_LOOP_EXIT
	        if (tmp[0] != 0)
	        {
		  continue;
	        }
#endif

		if (c->haveSaved)
		{
		    if (c->savedName)
		    {
		       memcpy(tmp, c->savedName, c->savedNameLen > 255 ? 255 : c->savedNameLen);
		       tmp[c->savedNameLen >255 ? 255 : c->savedNameLen] = 0;
		       if (nxagentFontLookUp(tmp))
		       {
#ifdef NXAGENT_DANGEROUS_XFONT_LOOP_EXIT
			 break;
#else
			 continue;
#endif
		       }
		       else tmp[0] = 0;
		    }
		}
		else
		{
		   memcpy(tmp, name, namelen > 255 ? 255 : namelen);
		   tmp[namelen > 255 ? 255 : namelen] = 0;
		   if (nxagentFontLookUp(tmp))
		   {
#ifdef NXAGENT_DANGEROUS_XFONT_LOOP_EXIT
		     break;
#else
		     continue;
#endif
		   }
		   else tmp[0] = 0;
		}
	    }

	    /*
	     * When we get an alias back, save our state and reset back to
	     * the start of the FPE looking for the specified name.  As
	     * soon as a real font is found for the alias, pop back to the
	     * old state
	     */
	    else if (err == FontNameAlias) {
		char	tmp_pattern[XLFDMAXFONTNAMELEN];
		/*
		 * when an alias recurses, we need to give
		 * the last FPE a chance to clean up; so we call
		 * it again, and assume that the error returned
		 * is BadFontName, indicating the alias resolution
		 * is complete.
		 */
		memmove(tmp_pattern, resolved, resolvedlen);
		if (c->haveSaved)
		{
		    char    *tmpname;
		    int     tmpnamelen;

		    tmpname = 0;
#ifdef HAS_XFONT2
		    (void) (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
			((void *) c->client, fpe, &tmpname, &tmpnamelen,
			 &tmpname, &tmpnamelen, c->current.private);
		    if (--aliascount <= 0)
		    {
			err = BadFontName;
			goto ContBadFontName;
		    }
		}
		else
		{
		    c->saved = c->current;
		    c->haveSaved = TRUE;
		    free(c->savedName);
		    c->savedName = (char *)malloc(namelen + 1);
		    if (c->savedName)
                    {
                        memmove(c->savedName, name, namelen);
                        c->savedName[namelen] = '\0';
                    }
		    c->savedNameLen = namelen;
		    aliascount = 20;
		}
		memmove(c->current.pattern, tmp_pattern, resolvedlen);
		c->current.patlen = resolvedlen;
		c->current.max_names = c->names->nnames + 1;
		c->current.current_fpe = -1;
		c->current.private = 0;
		err = BadFontName;
	    }
	}
	/*
	 * At the end of this FPE, step to the next.  If we've finished
	 * processing an alias, pop state back. If we've collected enough
	 * font names, quit.
	 */
	if (err == BadFontName) {
	  ContBadFontName: ;
	    c->current.list_started = FALSE;
	    c->current.current_fpe++;
#ifdef NXAGENT_SERVER
	    /* clearing a freed pointer helps for debugging */
	    c->current.private = 0;  /* BadFontName means private has been freed */
#endif
	    err = Successful;
	    if (c->haveSaved)
	    {
		if (c->names->nnames == c->current.max_names ||
			c->current.current_fpe == c->num_fpes) {
		    c->haveSaved = FALSE;
		    c->current = c->saved;
		    /* Give the saved namelist a chance to clean itself up */
		    continue;
		}
	    }
	    if (c->names->nnames == c->current.max_names)
		break;
	}
    }

bail:
finish:
#ifdef NXAGENT_DANGEROUS_XFONT_LOOP_EXIT
    /* if we allow above loop to be exited via break
       we need to free the private xfont data somehow. */
    if (c->current.list_started)
    {
      /* WARNING: this codes makes assumptions about an internal
	 private structure of libXfont and can therefore break with
	 ANY libXfont update! */
      typedef struct _LFWIData {
	FontNamesPtr    names;
	int                   current;
      } LFWIDataRec, *LFWIDataPtr;

      LFWIDataPtr data = c->current.private;
      if (data)
      {
#ifdef HAS_XFONT2
        xfont2_free_font_names(data->names);
#else
        FreeFontNames(data->names);
#endif
        free(data);
      }
    }
#endif

    if (strlen(tmp))
    {
#ifdef NXAGENT_FONTMATCH_DEBUG
      fprintf(stderr, "nxListFont changed (0) font to %s\n", tmp);
#endif
      memcpy(oc->fontname, tmp, strlen(tmp));
      oc->fnamelen = strlen(tmp);

      oc->origFontName = oc->fontname;
      oc->origFontNameLen = oc->fnamelen;
    }
    else
    {
        for (i = 0; i < c->names->nnames; i++)
	{
	  if (c->names->length[i] > 255)
	     continue;
	  else
	  {
	      memcpy(tmp, c->names->names[i], c->names->length[i]);
	      tmp[ c->names->length[i] ] = 0;
	      if (nxagentFontLookUp(tmp) == 0)
		continue;
	      memcpy(oc->fontname, tmp, strlen(tmp));
	      oc->fnamelen = strlen(tmp);

              oc->origFontName = oc->fontname;
              oc->origFontNameLen = oc->fnamelen;

#ifdef NXAGENT_FONTMATCH_DEBUG
	      fprintf(stderr, "nxListFont changed (1) font to %s\n",tmp);
#endif
	      break;
	  }
	}
    }

    if (c->slept)
    {
       ClientWakeup(client);
       #ifdef DEBUG
       fprintf(stderr, " NXdixfonts: nxdoListFont: client [%lx] wakeup.\n", client);
       #endif
    }
    for (i = 0; i < c->num_fpes; i++)
	FreeFPE(c->fpe_list[i]);
    free(c->fpe_list);
    free(c->savedName);
#ifdef HAS_XFONT2
    xfont2_free_font_names(c->names);
#else
    FreeFontNames(c->names);
#endif /* HAS_XFONT2 */
    free(c);
    free(fss);
    free(resolved);

    return doOpenFont(client, oc);
}


/* this is derived from dix/dixfonts.c:OpenFont() */
int
nxOpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
{
    nxFsPtr      fss;  /* NX Font Struct Ptr */
    LFclosurePtr c;    /* ListFont closure Ptr */
    OFclosurePtr oc;   /* OpenFont closure Ptr */
    int         i;
    FontPtr     cached = (FontPtr)0;

#ifdef FONTDEBUG
    char *f;
    f = (char *)malloc(lenfname + 1);
    memmove(f, pfontname, lenfname);
    f[lenfname] = '\0';
    ErrorF("OpenFont: fontname is \"%s\"\n", f);
    free(f);
#endif
    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
	return BadName;
    if (patternCache)
    {

    /*
    ** Check name cache.  If we find a cached version of this font that
    ** is cachable, immediately satisfy the request with it.  If we find
    ** a cached version of this font that is non-cachable, we do not
    ** satisfy the request with it.  Instead, we pass the FontPtr to the
    ** FPE's open_font code (the fontfile FPE in turn passes the
    ** information to the rasterizer; the fserve FPE ignores it).
    **
    ** Presumably, the font is marked non-cachable because the FPE has
    ** put some licensing restrictions on it.  If the FPE, using
    ** whatever logic it relies on, determines that it is willing to
    ** share this existing font with the client, then it has the option
    ** to return the FontPtr we passed it as the newly-opened font.
    ** This allows the FPE to exercise its licensing logic without
    ** having to create another instance of a font that already exists.
    */

#ifdef HAS_XFONT2
	cached = xfont2_find_cached_font_pattern(patternCache, pfontname, lenfname);
#else
	cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
#endif /* HAS_XFONT2 */
	if (cached && cached->info.cachable)
	{
	    if (!AddResource(fid, RT_FONT, (void *) cached))
		return BadAlloc;
	    cached->refcnt++;
	    return Success;
	}
    }
    if (!(fss = (nxFsPtr) malloc(sizeof(nxFs))))
        return BadAlloc;

    if (!(c = (LFclosurePtr) malloc(sizeof *c)))
    {
	free(fss);
	return BadAlloc;
    }

    c->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!c->fpe_list) {
	free(c);
	free(fss);
	return BadAlloc;
    }
#ifdef HAS_XFONT2
    c->names = xfont2_make_font_names_record(100);
#else
    c->names = MakeFontNamesRecord(100);
#endif /* HAS_XFONT2 */
    if (!c->names)
    {
	free(c->fpe_list);
	free(c);
	free(fss);
	return BadAlloc;
    }
    memmove( c->current.pattern, pfontname, lenfname);
    for (i = 0; i < num_fpes; i++) {
	c->fpe_list[i] = font_path_elements[i];
	UseFPE(c->fpe_list[i]);
    }
    c->client = client;
    c->num_fpes = num_fpes;
    c->current.patlen = lenfname;
    c->current.current_fpe = 0;
    c->current.max_names = nxagentMaxFontNames;
    c->current.list_started = FALSE;
    c->current.private = 0;
    c->haveSaved = FALSE;
    c->slept = FALSE;
    c->savedName = 0;

    oc = (OFclosurePtr) malloc(sizeof(OFclosureRec));
    if (!oc)
    {
      for (i = 0; i < c->num_fpes; i++)
        FreeFPE(c->fpe_list[i]);
      free(c->fpe_list);
      free(c);
      free(fss);
      return BadAlloc;
    }
    oc->fontname = (char *) malloc(256);/* I don't want to deal with future reallocs errors */
    oc->origFontName = pfontname;
    oc->origFontNameLen = lenfname;
    if (!oc->fontname) {
      for (i = 0; i < c->num_fpes; i++)
        FreeFPE(c->fpe_list[i]);
      free(c->fpe_list);
      free(c);
      free(oc);
      free(fss);
      return BadAlloc;
    }
    /*
     * copy the current FPE list, so that if it gets changed by another client
     * while we're blocking, the request still appears atomic
     */
    oc->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!oc->fpe_list) {
	free(oc->fontname);
	free(oc);
      for (i = 0; i < c->num_fpes; i++)
         FreeFPE(c->fpe_list[i]);
       free(c->fpe_list);
       free(c);
       free(fss);
       return BadAlloc;
    }
    memmove(oc->fontname, pfontname, lenfname);
    for (i = 0; i < num_fpes; i++) {
	oc->fpe_list[i] = font_path_elements[i];
	UseFPE(oc->fpe_list[i]);
    }
    oc->client = client;
    oc->fontid = fid;
    oc->current_fpe = 0;
    oc->num_fpes = num_fpes;
    oc->fnamelen = lenfname;
    oc->slept = FALSE;
    oc->flags = flags;
    oc->non_cachable_font = cached;
    fss->c=c;
    fss->oc=oc;
    nxdoListFontsAndAliases(client, fss);
    return Success;
}
