initial commit
[profile/ivi/xorg-x11-server.git] / dix / extension.c
1 /***********************************************************
2
3 Copyright 1987, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25
26 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its 
31 documentation for any purpose and without fee is hereby granted, 
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in 
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.  
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48 #ifdef HAVE_DIX_CONFIG_H
49 #include <dix-config.h>
50 #endif
51
52 #include <X11/X.h>
53 #include <X11/Xproto.h>
54 #include "misc.h"
55 #include "dixstruct.h"
56 #include "extnsionst.h"
57 #include "gcstruct.h"
58 #include "scrnintstr.h"
59 #include "dispatch.h"
60 #include "privates.h"
61 #include "registry.h"
62 #include "xace.h"
63
64 #define LAST_EVENT  128
65 #define LAST_ERROR 255
66
67 static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
68
69 int lastEvent = EXTENSION_EVENT_BASE;
70 static int lastError = FirstExtensionError;
71 static unsigned int NumExtensions = 0;
72
73 ExtensionEntry *
74 AddExtension(char *name, int NumEvents, int NumErrors, 
75              int (*MainProc)(ClientPtr c1), 
76              int (*SwappedMainProc)(ClientPtr c2), 
77              void (*CloseDownProc)(ExtensionEntry *e), 
78              unsigned short (*MinorOpcodeProc)(ClientPtr c3))
79 {
80     int i;
81     ExtensionEntry *ext, **newexts;
82
83     if (!MainProc || !SwappedMainProc || !MinorOpcodeProc)
84         return((ExtensionEntry *) NULL);
85     if ((lastEvent + NumEvents > LAST_EVENT) || 
86                 (unsigned)(lastError + NumErrors > LAST_ERROR)) {
87         LogMessage(X_ERROR, "Not enabling extension %s: maximum number of "
88                    "events or errors exceeded.\n", name);
89         return((ExtensionEntry *) NULL);
90     }
91
92     ext = calloc(sizeof (ExtensionEntry), 1);
93     if (!ext)
94         return NULL;
95     if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {
96         free(ext);
97         return NULL;
98     }
99     ext->name = malloc(strlen(name) + 1);
100     ext->num_aliases = 0;
101     ext->aliases = (char **)NULL;
102     if (!ext->name)
103     {
104         dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
105         free(ext);
106         return((ExtensionEntry *) NULL);
107     }
108     strcpy(ext->name,  name);
109     i = NumExtensions;
110     newexts = (ExtensionEntry **) realloc(extensions,
111                                            (i + 1) * sizeof(ExtensionEntry *));
112     if (!newexts)
113     {
114         free(ext->name);
115         dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
116         free(ext);
117         return((ExtensionEntry *) NULL);
118     }
119     NumExtensions++;
120     extensions = newexts;
121     extensions[i] = ext;
122     ext->index = i;
123     ext->base = i + EXTENSION_BASE;
124     ext->CloseDown = CloseDownProc;
125     ext->MinorOpcode = MinorOpcodeProc;
126     ProcVector[i + EXTENSION_BASE] = MainProc;
127     SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
128     if (NumEvents)
129     {
130         ext->eventBase = lastEvent;
131         ext->eventLast = lastEvent + NumEvents;
132         lastEvent += NumEvents;
133     }
134     else
135     {
136         ext->eventBase = 0;
137         ext->eventLast = 0;
138     }
139     if (NumErrors)
140     {
141         ext->errorBase = lastError;
142         ext->errorLast = lastError + NumErrors;
143         lastError += NumErrors;
144     }
145     else
146     {
147         ext->errorBase = 0;
148         ext->errorLast = 0;
149     }
150
151     RegisterExtensionNames(ext);
152     return ext;
153 }
154
155 Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
156 {
157     char *name;
158     char **aliases;
159
160     if (!ext)
161         return FALSE ;
162     aliases = (char **)realloc(ext->aliases,
163                                 (ext->num_aliases + 1) * sizeof(char *));
164     if (!aliases)
165         return FALSE;
166     ext->aliases = aliases;
167     name = malloc(strlen(alias) + 1);
168     if (!name)
169         return FALSE;
170     strcpy(name,  alias);
171     ext->aliases[ext->num_aliases] = name;
172     ext->num_aliases++;
173     return TRUE;
174 }
175
176 static int
177 FindExtension(char *extname, int len)
178 {
179     int i, j;
180
181     for (i=0; i<NumExtensions; i++)
182     {
183         if ((strlen(extensions[i]->name) == len) &&
184             !strncmp(extname, extensions[i]->name, len))
185             break;
186         for (j = extensions[i]->num_aliases; --j >= 0;)
187         {
188             if ((strlen(extensions[i]->aliases[j]) == len) &&
189                 !strncmp(extname, extensions[i]->aliases[j], len))
190                 break;
191         }
192         if (j >= 0) break;
193     }
194     return ((i == NumExtensions) ? -1 : i);
195 }
196
197 /*
198  * CheckExtension returns the extensions[] entry for the requested
199  * extension name.  Maybe this could just return a Bool instead?
200  */
201 ExtensionEntry *
202 CheckExtension(const char *extname)
203 {
204     int n;
205
206     n = FindExtension((char*)extname, strlen(extname));
207     if (n != -1)
208         return extensions[n];
209     else
210         return NULL;
211 }
212
213 /*
214  * Added as part of Xace.
215  */
216 ExtensionEntry *
217 GetExtensionEntry(int major)
218 {    
219     if (major < EXTENSION_BASE)
220         return NULL;
221     major -= EXTENSION_BASE;
222     if (major >= NumExtensions)
223         return NULL;
224     return extensions[major];
225 }
226
227 unsigned short
228 StandardMinorOpcode(ClientPtr client)
229 {
230     return ((xReq *)client->requestBuffer)->data;
231 }
232
233 unsigned short
234 MinorOpcodeOfRequest(ClientPtr client)
235 {
236     unsigned char major;
237
238     major = ((xReq *)client->requestBuffer)->reqType;
239     if (major < EXTENSION_BASE)
240         return 0;
241     major -= EXTENSION_BASE;
242     if (major >= NumExtensions)
243         return 0;
244     return (*extensions[major]->MinorOpcode)(client);
245 }
246
247 void
248 CloseDownExtensions(void)
249 {
250     int i,j;
251
252     for (i = NumExtensions - 1; i >= 0; i--)
253     {
254         if (extensions[i]->CloseDown)
255             extensions[i]->CloseDown(extensions[i]);
256         NumExtensions = i;
257         free(extensions[i]->name);
258         for (j = extensions[i]->num_aliases; --j >= 0;)
259             free(extensions[i]->aliases[j]);
260         free(extensions[i]->aliases);
261         dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION);
262         free(extensions[i]);
263     }
264     free(extensions);
265     extensions = (ExtensionEntry **)NULL;
266     lastEvent = EXTENSION_EVENT_BASE;
267     lastError = FirstExtensionError;
268 }
269
270 int
271 ProcQueryExtension(ClientPtr client)
272 {
273     xQueryExtensionReply reply;
274     int i;
275     REQUEST(xQueryExtensionReq);
276
277     REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
278
279     memset(&reply, 0, sizeof(xQueryExtensionReply));
280     reply.type = X_Reply;
281     reply.length = 0;
282     reply.major_opcode = 0;
283     reply.sequenceNumber = client->sequence;
284
285     if ( ! NumExtensions )
286         reply.present = xFalse;
287     else
288     {
289         i = FindExtension((char *)&stuff[1], stuff->nbytes);
290         if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
291             reply.present = xFalse;
292         else
293         {            
294             reply.present = xTrue;
295             reply.major_opcode = extensions[i]->base;
296             reply.first_event = extensions[i]->eventBase;
297             reply.first_error = extensions[i]->errorBase;
298         }
299     }
300     WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
301     return Success;
302 }
303
304 int
305 ProcListExtensions(ClientPtr client)
306 {
307     xListExtensionsReply reply;
308     char *bufptr, *buffer;
309     int total_length = 0;
310
311     REQUEST_SIZE_MATCH(xReq);
312
313     memset(&reply, 0, sizeof(xListExtensionsReply));
314     reply.type = X_Reply;
315     reply.nExtensions = 0;
316     reply.length = 0;
317     reply.sequenceNumber = client->sequence;
318     buffer = NULL;
319
320     if ( NumExtensions )
321     {
322         int i, j;
323
324         for (i=0;  i<NumExtensions; i++)
325         {
326             /* call callbacks to find out whether to show extension */
327             if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
328                 continue;
329
330             total_length += strlen(extensions[i]->name) + 1;
331             reply.nExtensions += 1 + extensions[i]->num_aliases;
332             for (j = extensions[i]->num_aliases; --j >= 0;)
333                 total_length += strlen(extensions[i]->aliases[j]) + 1;
334         }
335         reply.length = bytes_to_int32(total_length);
336         buffer = bufptr = malloc(total_length);
337         if (!buffer)
338             return BadAlloc;
339         for (i=0;  i<NumExtensions; i++)
340         {
341             int len;
342             if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
343                 continue;
344
345             *bufptr++ = len = strlen(extensions[i]->name);
346             memmove(bufptr, extensions[i]->name,  len);
347             bufptr += len;
348             for (j = extensions[i]->num_aliases; --j >= 0;)
349             {
350                 *bufptr++ = len = strlen(extensions[i]->aliases[j]);
351                 memmove(bufptr, extensions[i]->aliases[j],  len);
352                 bufptr += len;
353             }
354         }
355     }
356     WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
357     if (reply.length)
358     {
359         WriteToClient(client, total_length, buffer);
360         free(buffer);
361     }
362     return Success;
363 }