1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg******************************************************************/
47706f2543Smrg
48706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
49706f2543Smrg#include <dix-config.h>
50706f2543Smrg#endif
51706f2543Smrg
52706f2543Smrg#include <X11/X.h>
53706f2543Smrg#include <X11/Xproto.h>
54706f2543Smrg#include "windowstr.h"
55706f2543Smrg#include "propertyst.h"
56706f2543Smrg#include "dixstruct.h"
57706f2543Smrg#include "dispatch.h"
58706f2543Smrg#include "swaprep.h"
59706f2543Smrg#include "xace.h"
60706f2543Smrg
61706f2543Smrg/*****************************************************************
62706f2543Smrg * Property Stuff
63706f2543Smrg *
64706f2543Smrg *    dixLookupProperty, dixChangeProperty, DeleteProperty
65706f2543Smrg *
66706f2543Smrg *   Properties belong to windows.  The list of properties should not be
67706f2543Smrg *   traversed directly.  Instead, use the three functions listed above.
68706f2543Smrg *
69706f2543Smrg *****************************************************************/
70706f2543Smrg
71706f2543Smrg#ifdef notdef
72706f2543Smrgstatic void
73706f2543SmrgPrintPropertys(WindowPtr pWin)
74706f2543Smrg{
75706f2543Smrg    PropertyPtr pProp;
76706f2543Smrg    int j;
77706f2543Smrg
78706f2543Smrg    pProp = pWin->userProps;
79706f2543Smrg    while (pProp)
80706f2543Smrg    {
81706f2543Smrg        ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type);
82706f2543Smrg        ErrorF("[dix] property format: %d\n", pProp->format);
83706f2543Smrg        ErrorF("[dix] property data: \n");
84706f2543Smrg        for (j=0; j<(pProp->format/8)*pProp->size; j++)
85706f2543Smrg           ErrorF("[dix] %c\n", pProp->data[j]);
86706f2543Smrg        pProp = pProp->next;
87706f2543Smrg    }
88706f2543Smrg}
89706f2543Smrg#endif
90706f2543Smrg
91706f2543Smrgint
92706f2543SmrgdixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
93706f2543Smrg		  ClientPtr client, Mask access_mode)
94706f2543Smrg{
95706f2543Smrg    PropertyPtr pProp;
96706f2543Smrg    int rc = BadMatch;
97706f2543Smrg    client->errorValue = propertyName;
98706f2543Smrg
99706f2543Smrg    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
100706f2543Smrg	if (pProp->propertyName == propertyName)
101706f2543Smrg	    break;
102706f2543Smrg
103706f2543Smrg    if (pProp)
104706f2543Smrg	rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode);
105706f2543Smrg    *result = pProp;
106706f2543Smrg    return rc;
107706f2543Smrg}
108706f2543Smrg
109706f2543Smrgstatic void
110706f2543SmrgdeliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom)
111706f2543Smrg{
112706f2543Smrg    xEvent event;
113706f2543Smrg
114706f2543Smrg    memset(&event, 0, sizeof(xEvent));
115706f2543Smrg    event.u.u.type = PropertyNotify;
116706f2543Smrg    event.u.property.window = pWin->drawable.id;
117706f2543Smrg    event.u.property.state = state;
118706f2543Smrg    event.u.property.atom = atom;
119706f2543Smrg    event.u.property.time = currentTime.milliseconds;
120706f2543Smrg    DeliverEvents(pWin, &event, 1, (WindowPtr)NULL);
121706f2543Smrg}
122706f2543Smrg
123706f2543Smrgint
124706f2543SmrgProcRotateProperties(ClientPtr client)
125706f2543Smrg{
126706f2543Smrg    int     i, j, delta, rc;
127706f2543Smrg    REQUEST(xRotatePropertiesReq);
128706f2543Smrg    WindowPtr pWin;
129706f2543Smrg    Atom * atoms;
130706f2543Smrg    PropertyPtr * props;               /* array of pointer */
131706f2543Smrg    PropertyPtr pProp, saved;
132706f2543Smrg
133706f2543Smrg    REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
134706f2543Smrg    UpdateCurrentTime();
135706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
136706f2543Smrg    if (rc != Success || stuff->nAtoms <= 0)
137706f2543Smrg        return rc;
138706f2543Smrg
139706f2543Smrg    atoms = (Atom *) & stuff[1];
140706f2543Smrg    props = malloc(stuff->nAtoms * sizeof(PropertyPtr));
141706f2543Smrg    saved = malloc(stuff->nAtoms * sizeof(PropertyRec));
142706f2543Smrg    if (!props || !saved) {
143706f2543Smrg	rc = BadAlloc;
144706f2543Smrg	goto out;
145706f2543Smrg    }
146706f2543Smrg
147706f2543Smrg    for (i = 0; i < stuff->nAtoms; i++)
148706f2543Smrg    {
149706f2543Smrg        if (!ValidAtom(atoms[i])) {
150706f2543Smrg	    rc = BadAtom;
151706f2543Smrg	    client->errorValue = atoms[i];
152706f2543Smrg	    goto out;
153706f2543Smrg        }
154706f2543Smrg        for (j = i + 1; j < stuff->nAtoms; j++)
155706f2543Smrg            if (atoms[j] == atoms[i])
156706f2543Smrg            {
157706f2543Smrg		rc = BadMatch;
158706f2543Smrg		goto out;
159706f2543Smrg            }
160706f2543Smrg
161706f2543Smrg	rc = dixLookupProperty(&pProp, pWin, atoms[i], client,
162706f2543Smrg			       DixReadAccess|DixWriteAccess);
163706f2543Smrg	if (rc != Success)
164706f2543Smrg	    goto out;
165706f2543Smrg
166706f2543Smrg        props[i] = pProp;
167706f2543Smrg	saved[i] = *pProp;
168706f2543Smrg    }
169706f2543Smrg    delta = stuff->nPositions;
170706f2543Smrg
171706f2543Smrg    /* If the rotation is a complete 360 degrees, then moving the properties
172706f2543Smrg	around and generating PropertyNotify events should be skipped. */
173706f2543Smrg
174706f2543Smrg    if (abs(delta) % stuff->nAtoms)
175706f2543Smrg    {
176706f2543Smrg	while (delta < 0)                  /* faster if abs value is small */
177706f2543Smrg            delta += stuff->nAtoms;
178706f2543Smrg    	for (i = 0; i < stuff->nAtoms; i++)
179706f2543Smrg 	{
180706f2543Smrg	    j = (i + delta) % stuff->nAtoms;
181706f2543Smrg	    deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]);
182706f2543Smrg
183706f2543Smrg	    /* Preserve name and devPrivates */
184706f2543Smrg	    props[j]->type = saved[i].type;
185706f2543Smrg	    props[j]->format = saved[i].format;
186706f2543Smrg	    props[j]->size = saved[i].size;
187706f2543Smrg	    props[j]->data = saved[i].data;
188706f2543Smrg	}
189706f2543Smrg    }
190706f2543Smrgout:
191706f2543Smrg    free(saved);
192706f2543Smrg    free(props);
193706f2543Smrg    return rc;
194706f2543Smrg}
195706f2543Smrg
196706f2543Smrgint
197706f2543SmrgProcChangeProperty(ClientPtr client)
198706f2543Smrg{
199706f2543Smrg    WindowPtr pWin;
200706f2543Smrg    char format, mode;
201706f2543Smrg    unsigned long len;
202c8c3bf63Smrg    int sizeInBytes, err;
203c8c3bf63Smrg    uint64_t totalSize;
204706f2543Smrg    REQUEST(xChangePropertyReq);
205706f2543Smrg
206706f2543Smrg    REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
207706f2543Smrg    UpdateCurrentTime();
208706f2543Smrg    format = stuff->format;
209706f2543Smrg    mode = stuff->mode;
210706f2543Smrg    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
211706f2543Smrg	(mode != PropModePrepend))
212706f2543Smrg    {
213706f2543Smrg	client->errorValue = mode;
214706f2543Smrg	return BadValue;
215706f2543Smrg    }
216706f2543Smrg    if ((format != 8) && (format != 16) && (format != 32))
217706f2543Smrg    {
218706f2543Smrg	client->errorValue = format;
219706f2543Smrg        return BadValue;
220706f2543Smrg    }
221706f2543Smrg    len = stuff->nUnits;
222706f2543Smrg    if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq)))
223706f2543Smrg	return BadLength;
224706f2543Smrg    sizeInBytes = format>>3;
225706f2543Smrg    totalSize = len * sizeInBytes;
226706f2543Smrg    REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
227706f2543Smrg
228706f2543Smrg    err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
229706f2543Smrg    if (err != Success)
230706f2543Smrg	return err;
231706f2543Smrg    if (!ValidAtom(stuff->property))
232706f2543Smrg    {
233706f2543Smrg	client->errorValue = stuff->property;
234706f2543Smrg	return BadAtom;
235706f2543Smrg    }
236706f2543Smrg    if (!ValidAtom(stuff->type))
237706f2543Smrg    {
238706f2543Smrg	client->errorValue = stuff->type;
239706f2543Smrg	return BadAtom;
240706f2543Smrg    }
241706f2543Smrg
242706f2543Smrg    err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type,
243706f2543Smrg				  (int)format, (int)mode, len, &stuff[1],
244706f2543Smrg				  TRUE);
245706f2543Smrg    if (err != Success)
246706f2543Smrg	return err;
247706f2543Smrg    else
248706f2543Smrg	return Success;
249706f2543Smrg}
250706f2543Smrg
251706f2543Smrgint
252706f2543SmrgdixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
253706f2543Smrg			Atom type, int format, int mode, unsigned long len,
254706f2543Smrg			pointer value, Bool sendevent)
255706f2543Smrg{
256706f2543Smrg    PropertyPtr pProp;
257706f2543Smrg    PropertyRec savedProp;
258706f2543Smrg    int sizeInBytes, totalSize, rc;
259706f2543Smrg    unsigned char *data;
260706f2543Smrg    Mask access_mode;
261706f2543Smrg
262706f2543Smrg    sizeInBytes = format>>3;
263706f2543Smrg    totalSize = len * sizeInBytes;
264706f2543Smrg    access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess;
265706f2543Smrg
266706f2543Smrg    /* first see if property already exists */
267706f2543Smrg    rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode);
268706f2543Smrg
269706f2543Smrg    if (rc == BadMatch)   /* just add to list */
270706f2543Smrg    {
271706f2543Smrg	if (!pWin->optional && !MakeWindowOptional (pWin))
272706f2543Smrg	    return BadAlloc;
273706f2543Smrg	pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY);
274706f2543Smrg	if (!pProp)
275706f2543Smrg	    return BadAlloc;
276706f2543Smrg        data = malloc(totalSize);
277706f2543Smrg	if (!data && len)
278706f2543Smrg	{
279706f2543Smrg	    dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
280706f2543Smrg	    return BadAlloc;
281706f2543Smrg	}
282706f2543Smrg        memcpy(data, value, totalSize);
283706f2543Smrg        pProp->propertyName = property;
284706f2543Smrg        pProp->type = type;
285706f2543Smrg        pProp->format = format;
286706f2543Smrg        pProp->data = data;
287706f2543Smrg	pProp->size = len;
288706f2543Smrg	rc = XaceHookPropertyAccess(pClient, pWin, &pProp,
289706f2543Smrg				    DixCreateAccess|DixWriteAccess);
290706f2543Smrg	if (rc != Success) {
291706f2543Smrg	    free(data);
292706f2543Smrg	    dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
293706f2543Smrg	    pClient->errorValue = property;
294706f2543Smrg	    return rc;
295706f2543Smrg	}
296706f2543Smrg        pProp->next = pWin->optional->userProps;
297706f2543Smrg        pWin->optional->userProps = pProp;
298706f2543Smrg    }
299706f2543Smrg    else if (rc == Success)
300706f2543Smrg    {
301706f2543Smrg	/* To append or prepend to a property the request format and type
302706f2543Smrg		must match those of the already defined property.  The
303706f2543Smrg		existing format and type are irrelevant when using the mode
304706f2543Smrg		"PropModeReplace" since they will be written over. */
305706f2543Smrg
306706f2543Smrg        if ((format != pProp->format) && (mode != PropModeReplace))
307706f2543Smrg	    return BadMatch;
308706f2543Smrg        if ((pProp->type != type) && (mode != PropModeReplace))
309706f2543Smrg            return BadMatch;
310706f2543Smrg
311706f2543Smrg	/* save the old values for later */
312706f2543Smrg	savedProp = *pProp;
313706f2543Smrg
314706f2543Smrg        if (mode == PropModeReplace)
315706f2543Smrg        {
316706f2543Smrg	    data = malloc(totalSize);
317706f2543Smrg	    if (!data && len)
318706f2543Smrg		return BadAlloc;
319706f2543Smrg	    memcpy(data, value, totalSize);
320706f2543Smrg	    pProp->data = data;
321706f2543Smrg	    pProp->size = len;
322706f2543Smrg    	    pProp->type = type;
323706f2543Smrg	    pProp->format = format;
324706f2543Smrg	}
325706f2543Smrg	else if (len == 0)
326706f2543Smrg	{
327706f2543Smrg	    /* do nothing */
328706f2543Smrg	}
329706f2543Smrg        else if (mode == PropModeAppend)
330706f2543Smrg        {
331706f2543Smrg	    data = malloc((pProp->size + len) * sizeInBytes);
332706f2543Smrg	    if (!data)
333706f2543Smrg		return BadAlloc;
334706f2543Smrg	    memcpy(data, pProp->data, pProp->size * sizeInBytes);
335706f2543Smrg	    memcpy(data + pProp->size * sizeInBytes, value, totalSize);
336706f2543Smrg            pProp->data = data;
337706f2543Smrg            pProp->size += len;
338706f2543Smrg	}
339706f2543Smrg        else if (mode == PropModePrepend)
340706f2543Smrg        {
341706f2543Smrg            data = malloc(sizeInBytes * (len + pProp->size));
342706f2543Smrg	    if (!data)
343706f2543Smrg		return BadAlloc;
344706f2543Smrg            memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes);
345706f2543Smrg            memcpy(data, value, totalSize);
346706f2543Smrg            pProp->data = data;
347706f2543Smrg            pProp->size += len;
348706f2543Smrg	}
349706f2543Smrg
350706f2543Smrg	/* Allow security modules to check the new content */
351706f2543Smrg	access_mode |= DixPostAccess;
352706f2543Smrg	rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode);
353706f2543Smrg	if (rc == Success)
354706f2543Smrg	{
355706f2543Smrg	    if (savedProp.data != pProp->data)
356706f2543Smrg		free(savedProp.data);
357706f2543Smrg	}
358706f2543Smrg	else
359706f2543Smrg	{
360706f2543Smrg	    if (savedProp.data != pProp->data)
361706f2543Smrg		free(pProp->data);
362706f2543Smrg	    *pProp = savedProp;
363706f2543Smrg	    return rc;
364706f2543Smrg	}
365706f2543Smrg    }
366706f2543Smrg    else
367706f2543Smrg	return rc;
368706f2543Smrg
369706f2543Smrg    if (sendevent)
370706f2543Smrg	deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName);
371706f2543Smrg
372706f2543Smrg    return Success;
373706f2543Smrg}
374706f2543Smrg
375706f2543Smrgint
376706f2543SmrgChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format,
377706f2543Smrg		     int mode, unsigned long len, pointer value,
378706f2543Smrg		     Bool sendevent)
379706f2543Smrg{
380706f2543Smrg    return dixChangeWindowProperty(serverClient, pWin, property, type, format,
381706f2543Smrg				   mode, len, value, sendevent);
382706f2543Smrg}
383706f2543Smrg
384706f2543Smrgint
385706f2543SmrgDeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
386706f2543Smrg{
387706f2543Smrg    PropertyPtr pProp, prevProp;
388706f2543Smrg    int rc;
389706f2543Smrg
390706f2543Smrg    rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess);
391706f2543Smrg    if (rc == BadMatch)
392706f2543Smrg	return Success; /* Succeed if property does not exist */
393706f2543Smrg
394706f2543Smrg    if (rc == Success) {
395706f2543Smrg	if (pWin->optional->userProps == pProp) {
396706f2543Smrg	    /* Takes care of head */
397706f2543Smrg            if (!(pWin->optional->userProps = pProp->next))
398706f2543Smrg		CheckWindowOptionalNeed (pWin);
399706f2543Smrg	} else {
400706f2543Smrg	    /* Need to traverse to find the previous element */
401706f2543Smrg	    prevProp = pWin->optional->userProps;
402706f2543Smrg	    while (prevProp->next != pProp)
403706f2543Smrg		prevProp = prevProp->next;
404706f2543Smrg	    prevProp->next = pProp->next;
405706f2543Smrg	}
406706f2543Smrg
407706f2543Smrg	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
408706f2543Smrg	free(pProp->data);
409706f2543Smrg	dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
410706f2543Smrg    }
411706f2543Smrg    return rc;
412706f2543Smrg}
413706f2543Smrg
414706f2543Smrgvoid
415706f2543SmrgDeleteAllWindowProperties(WindowPtr pWin)
416706f2543Smrg{
417706f2543Smrg    PropertyPtr pProp, pNextProp;
418706f2543Smrg
419706f2543Smrg    pProp = wUserProps (pWin);
420706f2543Smrg    while (pProp)
421706f2543Smrg    {
422706f2543Smrg	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
423706f2543Smrg	pNextProp = pProp->next;
424706f2543Smrg        free(pProp->data);
425706f2543Smrg	dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
426706f2543Smrg	pProp = pNextProp;
427706f2543Smrg    }
428706f2543Smrg
429706f2543Smrg    if (pWin->optional)
430706f2543Smrg        pWin->optional->userProps = NULL;
431706f2543Smrg}
432706f2543Smrg
433706f2543Smrgstatic int
434706f2543SmrgNullPropertyReply(
435706f2543Smrg    ClientPtr client,
436706f2543Smrg    ATOM propertyType,
437706f2543Smrg    int format,
438706f2543Smrg    xGetPropertyReply *reply)
439706f2543Smrg{
440706f2543Smrg    reply->nItems = 0;
441706f2543Smrg    reply->length = 0;
442706f2543Smrg    reply->bytesAfter = 0;
443706f2543Smrg    reply->propertyType = propertyType;
444706f2543Smrg    reply->format = format;
445706f2543Smrg    WriteReplyToClient(client, sizeof(xGenericReply), reply);
446706f2543Smrg    return Success;
447706f2543Smrg}
448706f2543Smrg
449706f2543Smrg/*****************
450706f2543Smrg * GetProperty
451706f2543Smrg *    If type Any is specified, returns the property from the specified
452706f2543Smrg *    window regardless of its type.  If a type is specified, returns the
453706f2543Smrg *    property only if its type equals the specified type.
454706f2543Smrg *    If delete is True and a property is returned, the property is also
455706f2543Smrg *    deleted from the window and a PropertyNotify event is generated on the
456706f2543Smrg *    window.
457706f2543Smrg *****************/
458706f2543Smrg
459706f2543Smrgint
460706f2543SmrgProcGetProperty(ClientPtr client)
461706f2543Smrg{
462706f2543Smrg    PropertyPtr pProp, prevProp;
463706f2543Smrg    unsigned long n, len, ind;
464706f2543Smrg    int rc;
465706f2543Smrg    WindowPtr pWin;
466706f2543Smrg    xGetPropertyReply reply;
467706f2543Smrg    Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
468706f2543Smrg    REQUEST(xGetPropertyReq);
469706f2543Smrg
470706f2543Smrg    REQUEST_SIZE_MATCH(xGetPropertyReq);
471706f2543Smrg    if (stuff->delete) {
472706f2543Smrg	UpdateCurrentTime();
473706f2543Smrg	win_mode |= DixSetPropAccess;
474706f2543Smrg	prop_mode |= DixDestroyAccess;
475706f2543Smrg    }
476706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, win_mode);
477706f2543Smrg    if (rc != Success)
478706f2543Smrg	return (rc == BadMatch) ? BadWindow : rc;
479706f2543Smrg
480706f2543Smrg    if (!ValidAtom(stuff->property))
481706f2543Smrg    {
482706f2543Smrg	client->errorValue = stuff->property;
483706f2543Smrg	return BadAtom;
484706f2543Smrg    }
485706f2543Smrg    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
486706f2543Smrg    {
487706f2543Smrg	client->errorValue = stuff->delete;
488706f2543Smrg	return BadValue;
489706f2543Smrg    }
490706f2543Smrg    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
491706f2543Smrg    {
492706f2543Smrg	client->errorValue = stuff->type;
493706f2543Smrg	return BadAtom;
494706f2543Smrg    }
495706f2543Smrg
496706f2543Smrg    memset(&reply, 0, sizeof(xGetPropertyReply));
497706f2543Smrg    reply.type = X_Reply;
498706f2543Smrg    reply.sequenceNumber = client->sequence;
499706f2543Smrg
500706f2543Smrg    rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode);
501706f2543Smrg    if (rc == BadMatch)
502706f2543Smrg	return NullPropertyReply(client, None, 0, &reply);
503706f2543Smrg    else if (rc != Success)
504706f2543Smrg	return rc;
505706f2543Smrg
506706f2543Smrg    /* If the request type and actual type don't match. Return the
507706f2543Smrg    property information, but not the data. */
508706f2543Smrg
509706f2543Smrg    if (((stuff->type != pProp->type) &&
510706f2543Smrg	 (stuff->type != AnyPropertyType))
511706f2543Smrg       )
512706f2543Smrg    {
513706f2543Smrg	reply.bytesAfter = pProp->size;
514706f2543Smrg	reply.format = pProp->format;
515706f2543Smrg	reply.length = 0;
516706f2543Smrg	reply.nItems = 0;
517706f2543Smrg	reply.propertyType = pProp->type;
518706f2543Smrg	WriteReplyToClient(client, sizeof(xGenericReply), &reply);
519706f2543Smrg	return Success;
520706f2543Smrg    }
521706f2543Smrg
522706f2543Smrg/*
523706f2543Smrg *  Return type, format, value to client
524706f2543Smrg */
525706f2543Smrg    n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */
526706f2543Smrg    ind = stuff->longOffset << 2;
527706f2543Smrg
528706f2543Smrg   /* If longOffset is invalid such that it causes "len" to
529706f2543Smrg	    be negative, it's a value error. */
530706f2543Smrg
531706f2543Smrg    if (n < ind)
532706f2543Smrg    {
533706f2543Smrg	client->errorValue = stuff->longOffset;
534706f2543Smrg	return BadValue;
535706f2543Smrg    }
536706f2543Smrg
537706f2543Smrg    len = min(n - ind, 4 * stuff->longLength);
538706f2543Smrg
539706f2543Smrg    reply.bytesAfter = n - (ind + len);
540706f2543Smrg    reply.format = pProp->format;
541706f2543Smrg    reply.length = bytes_to_int32(len);
542706f2543Smrg    reply.nItems = len / (pProp->format / 8 );
543706f2543Smrg    reply.propertyType = pProp->type;
544706f2543Smrg
545706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0))
546706f2543Smrg	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
547706f2543Smrg
548706f2543Smrg    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
549706f2543Smrg    if (len)
550706f2543Smrg    {
551706f2543Smrg	switch (reply.format) {
552706f2543Smrg	case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
553706f2543Smrg	case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
554706f2543Smrg	default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
555706f2543Smrg	}
556706f2543Smrg	WriteSwappedDataToClient(client, len,
557706f2543Smrg				 (char *)pProp->data + ind);
558706f2543Smrg    }
559706f2543Smrg
560706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0)) {
561706f2543Smrg	/* Delete the Property */
562706f2543Smrg	if (pWin->optional->userProps == pProp) {
563706f2543Smrg	    /* Takes care of head */
564706f2543Smrg            if (!(pWin->optional->userProps = pProp->next))
565706f2543Smrg		CheckWindowOptionalNeed (pWin);
566706f2543Smrg	} else {
567706f2543Smrg	    /* Need to traverse to find the previous element */
568706f2543Smrg	    prevProp = pWin->optional->userProps;
569706f2543Smrg	    while (prevProp->next != pProp)
570706f2543Smrg		prevProp = prevProp->next;
571706f2543Smrg	    prevProp->next = pProp->next;
572706f2543Smrg	}
573706f2543Smrg
574706f2543Smrg	free(pProp->data);
575706f2543Smrg	dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
576706f2543Smrg    }
577706f2543Smrg    return Success;
578706f2543Smrg}
579706f2543Smrg
580706f2543Smrgint
581706f2543SmrgProcListProperties(ClientPtr client)
582706f2543Smrg{
583706f2543Smrg    Atom *pAtoms = NULL, *temppAtoms;
584706f2543Smrg    xListPropertiesReply xlpr;
585706f2543Smrg    int	rc, numProps = 0;
586706f2543Smrg    WindowPtr pWin;
587706f2543Smrg    PropertyPtr pProp, realProp;
588706f2543Smrg    REQUEST(xResourceReq);
589706f2543Smrg
590706f2543Smrg    REQUEST_SIZE_MATCH(xResourceReq);
591706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess);
592706f2543Smrg    if (rc != Success)
593706f2543Smrg        return rc;
594706f2543Smrg
595706f2543Smrg    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
596706f2543Smrg	numProps++;
597706f2543Smrg
598706f2543Smrg    if (numProps && !(pAtoms = malloc(numProps * sizeof(Atom))))
599706f2543Smrg	return BadAlloc;
600706f2543Smrg
601706f2543Smrg    numProps = 0;
602706f2543Smrg    temppAtoms = pAtoms;
603706f2543Smrg    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
604706f2543Smrg	realProp = pProp;
605706f2543Smrg	rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
606706f2543Smrg	if (rc == Success && realProp == pProp) {
607706f2543Smrg	    *temppAtoms++ = pProp->propertyName;
608706f2543Smrg	    numProps++;
609706f2543Smrg	}
610706f2543Smrg    }
611706f2543Smrg
612706f2543Smrg    xlpr.type = X_Reply;
613706f2543Smrg    xlpr.nProperties = numProps;
614706f2543Smrg    xlpr.length = bytes_to_int32(numProps * sizeof(Atom));
615706f2543Smrg    xlpr.sequenceNumber = client->sequence;
616706f2543Smrg    WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
617706f2543Smrg    if (numProps)
618706f2543Smrg    {
619706f2543Smrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
620706f2543Smrg        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
621706f2543Smrg    }
622706f2543Smrg    free(pAtoms);
623706f2543Smrg    return Success;
624706f2543Smrg}
625706f2543Smrg
626706f2543Smrgint
627706f2543SmrgProcDeleteProperty(ClientPtr client)
628706f2543Smrg{
629706f2543Smrg    WindowPtr pWin;
630706f2543Smrg    REQUEST(xDeletePropertyReq);
631706f2543Smrg    int result;
632706f2543Smrg
633706f2543Smrg    REQUEST_SIZE_MATCH(xDeletePropertyReq);
634706f2543Smrg    UpdateCurrentTime();
635706f2543Smrg    result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
636706f2543Smrg    if (result != Success)
637706f2543Smrg        return result;
638706f2543Smrg    if (!ValidAtom(stuff->property))
639706f2543Smrg    {
640706f2543Smrg	client->errorValue = stuff->property;
641706f2543Smrg	return BadAtom;
642706f2543Smrg    }
643706f2543Smrg
644706f2543Smrg    return DeleteProperty(client, pWin, stuff->property);
645706f2543Smrg}
646