#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "gcstruct.h"
#include "scrnintstr.h"
#include "dispatch.h"
#include "privates.h"
#include "registry.h"
#include "xace.h"
#define LAST_EVENT 128
#define LAST_ERROR 255
static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
int lastEvent = EXTENSION_EVENT_BASE;
static int lastError = FirstExtensionError;
static unsigned int NumExtensions = 0;
ExtensionEntry *
AddExtension(char *name, int NumEvents, int NumErrors,
int (*MainProc)(ClientPtr c1),
int (*SwappedMainProc)(ClientPtr c2),
void (*CloseDownProc)(ExtensionEntry *e),
unsigned short (*MinorOpcodeProc)(ClientPtr c3))
{
int i;
ExtensionEntry *ext, **newexts;
if (!MainProc || !SwappedMainProc || !MinorOpcodeProc)
return((ExtensionEntry *) NULL);
if ((lastEvent + NumEvents > LAST_EVENT) ||
(unsigned)(lastError + NumErrors > LAST_ERROR)) {
LogMessage(X_ERROR, "Not enabling extension %s: maximum number of "
"events or errors exceeded.\n", name);
return((ExtensionEntry *) NULL);
}
ext = calloc(sizeof (ExtensionEntry), 1);
if (!ext)
return NULL;
if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {
free(ext);
return NULL;
}
ext->name = strdup(name);
ext->num_aliases = 0;
ext->aliases = (char **)NULL;
if (!ext->name)
{
dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
free(ext);
return((ExtensionEntry *) NULL);
}
i = NumExtensions;
newexts = (ExtensionEntry **) realloc(extensions,
(i + 1) * sizeof(ExtensionEntry *));
if (!newexts)
{
free(ext->name);
dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
free(ext);
return((ExtensionEntry *) NULL);
}
NumExtensions++;
extensions = newexts;
extensions[i] = ext;
ext->index = i;
ext->base = i + EXTENSION_BASE;
ext->CloseDown = CloseDownProc;
ext->MinorOpcode = MinorOpcodeProc;
ProcVector[i + EXTENSION_BASE] = MainProc;
SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
if (NumEvents)
{
ext->eventBase = lastEvent;
ext->eventLast = lastEvent + NumEvents;
lastEvent += NumEvents;
}
else
{
ext->eventBase = 0;
ext->eventLast = 0;
}
if (NumErrors)
{
ext->errorBase = lastError;
ext->errorLast = lastError + NumErrors;
lastError += NumErrors;
}
else
{
ext->errorBase = 0;
ext->errorLast = 0;
}
RegisterExtensionNames(ext);
return ext;
}
Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
{
char *name;
char **aliases;
if (!ext)
return FALSE ;
aliases = (char **)realloc(ext->aliases,
(ext->num_aliases + 1) * sizeof(char *));
if (!aliases)
return FALSE;
ext->aliases = aliases;
name = strdup(alias);
if (!name)
return FALSE;
ext->aliases[ext->num_aliases] = name;
ext->num_aliases++;
return TRUE;
}
static int
FindExtension(char *extname, int len)
{
int i, j;
for (i=0; i<NumExtensions; i++)
{
if ((strlen(extensions[i]->name) == len) &&
!strncmp(extname, extensions[i]->name, len))
break;
for (j = extensions[i]->num_aliases; --j >= 0;)
{
if ((strlen(extensions[i]->aliases[j]) == len) &&
!strncmp(extname, extensions[i]->aliases[j], len))
break;
}
if (j >= 0) break;
}
return ((i == NumExtensions) ? -1 : i);
}
ExtensionEntry *
CheckExtension(const char *extname)
{
int n;
n = FindExtension((char*)extname, strlen(extname));
if (n != -1)
return extensions[n];
else
return NULL;
}
ExtensionEntry *
GetExtensionEntry(int major)
{
if (major < EXTENSION_BASE)
return NULL;
major -= EXTENSION_BASE;
if (major >= NumExtensions)
return NULL;
return extensions[major];
}
unsigned short
StandardMinorOpcode(ClientPtr client)
{
return ((xReq *)client->requestBuffer)->data;
}
unsigned short
MinorOpcodeOfRequest(ClientPtr client)
{
unsigned char major;
major = ((xReq *)client->requestBuffer)->reqType;
if (major < EXTENSION_BASE)
return 0;
major -= EXTENSION_BASE;
if (major >= NumExtensions)
return 0;
return (*extensions[major]->MinorOpcode)(client);
}
void
CloseDownExtensions(void)
{
int i,j;
for (i = NumExtensions - 1; i >= 0; i--)
{
if (extensions[i]->CloseDown)
extensions[i]->CloseDown(extensions[i]);
NumExtensions = i;
free(extensions[i]->name);
for (j = extensions[i]->num_aliases; --j >= 0;)
free(extensions[i]->aliases[j]);
free(extensions[i]->aliases);
dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION);
free(extensions[i]);
}
free(extensions);
extensions = (ExtensionEntry **)NULL;
lastEvent = EXTENSION_EVENT_BASE;
lastError = FirstExtensionError;
}
int
ProcQueryExtension(ClientPtr client)
{
xQueryExtensionReply reply;
int i;
REQUEST(xQueryExtensionReq);
REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
memset(&reply, 0, sizeof(xQueryExtensionReply));
reply.type = X_Reply;
reply.length = 0;
reply.major_opcode = 0;
reply.sequenceNumber = client->sequence;
if ( ! NumExtensions )
reply.present = xFalse;
else
{
i = FindExtension((char *)&stuff[1], stuff->nbytes);
if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
reply.present = xFalse;
else
{
reply.present = xTrue;
reply.major_opcode = extensions[i]->base;
reply.first_event = extensions[i]->eventBase;
reply.first_error = extensions[i]->errorBase;
}
}
WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
return Success;
}
int
ProcListExtensions(ClientPtr client)
{
xListExtensionsReply reply;
char *bufptr, *buffer;
int total_length = 0;
REQUEST_SIZE_MATCH(xReq);
memset(&reply, 0, sizeof(xListExtensionsReply));
reply.type = X_Reply;
reply.nExtensions = 0;
reply.length = 0;
reply.sequenceNumber = client->sequence;
buffer = NULL;
if ( NumExtensions )
{
int i, j;
for (i=0; i<NumExtensions; i++)
{
if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
continue;
total_length += strlen(extensions[i]->name) + 1;
reply.nExtensions += 1 + extensions[i]->num_aliases;
for (j = extensions[i]->num_aliases; --j >= 0;)
total_length += strlen(extensions[i]->aliases[j]) + 1;
}
reply.length = bytes_to_int32(total_length);
buffer = bufptr = malloc(total_length);
if (!buffer)
return BadAlloc;
for (i=0; i<NumExtensions; i++)
{
int len;
if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
continue;
*bufptr++ = len = strlen(extensions[i]->name);
memmove(bufptr, extensions[i]->name, len);
bufptr += len;
for (j = extensions[i]->num_aliases; --j >= 0;)
{
*bufptr++ = len = strlen(extensions[i]->aliases[j]);
memmove(bufptr, extensions[i]->aliases[j], len);
bufptr += len;
}
}
}
WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
if (reply.length)
WriteToClient(client, total_length, buffer);
free(buffer);
return Success;
}