1/*
2 * misc utility routines
3 */
4/*
5
6Copyright 1990, 1991, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28 * Copyright 1990, 1991 Network Computing Devices;
29 * Portions Copyright 1987 by Digital Equipment Corporation
30 *
31 * Permission to use, copy, modify, distribute, and sell this software and
32 * its documentation for any purpose is hereby granted without fee, provided
33 * that the above copyright notice appear in all copies and that both that
34 * copyright notice and this permission notice appear in supporting
35 * documentation, and that the names of Network Computing Devices, or Digital
36 * not be used in advertising or publicity pertaining to distribution
37 * of the software without specific, written prior permission.
38 *
39 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
41 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
42 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
46 * THIS SOFTWARE.
47 */
48
49#include	"config.h"
50
51#define	XK_LATIN1
52
53#include	<difsutils.h>
54
55#include	<stdio.h>
56#include	<ctype.h>
57#include	"misc.h"
58#include	"globals.h"
59#include	"clientstr.h"
60#include	<X11/fonts/fontstruct.h>
61#include	<X11/keysymdef.h>
62
63#include	"authstr.h"
64#include	"auth.h"
65#include	"client.h"
66#include	"dispatch.h"
67
68static FontResolutionPtr default_resolutions;
69static int  num_resolutions;
70static int  default_point_size = 120;
71
72AuthContextPtr
73GetClientAuthorization(void)
74{
75    return currentClient->auth;
76}
77
78void
79SetDefaultPointSize(int ps)
80{
81    int         i;
82
83    default_point_size = ps;
84    for (i = 0; i < num_resolutions; i++)
85	default_resolutions[i].point_size = ps;
86}
87
88int
89SetDefaultResolutions(char *str)
90{
91    int         num,
92                numr = 0,
93                n;
94    char       *s;
95    FontResolutionPtr new,
96                nr;
97    int         state;
98
99    s = str;
100    while (*s) {		/* count commas */
101	if (*s == ',')
102	    numr++;
103	s++;
104    }
105
106    if ((numr % 2) != 1) {	/* must be multiple of 2 + 1 */
107	return FSBadResolution;
108    }
109    numr = (numr + 1) / 2;
110    nr = new = (FontResolutionPtr) FSallocarray(numr,
111                                                sizeof(FontResolutionRec));
112    if (!new)
113	return FSBadAlloc;
114    s = str;
115    num = 0;
116    state = 0;
117    while (*s) {
118	if (*s == ',') {
119	    if (state == 0) {
120		nr->x_resolution = num;
121		state++;
122	    } else {
123		state = 0;
124		nr->y_resolution = num;
125		nr->point_size = default_point_size;
126		nr++;
127	    }
128	    num = 0;
129	    s++;
130	    continue;
131	}
132	if (!isdigit(*s)) {
133	    FSfree((char *) new);
134	    return FSBadResolution;
135	}
136	n = *s - '0';
137	num = num * 10 + n;
138	s++;
139    }
140
141    /* do the last one */
142    assert(state == 1);
143    nr->y_resolution = num;
144    nr->point_size = default_point_size;
145
146    if (default_resolutions) {
147	FSfree((char *) default_resolutions);
148    }
149    default_resolutions = new;
150    num_resolutions = numr;
151    return FSSuccess;
152}
153
154FontResolutionPtr
155GetClientResolutions(int *num)
156{
157    /* return the client's if it has them, otherwise the default values */
158    if (currentClient->num_resolutions) {
159	*num = currentClient->num_resolutions;
160	return (FontResolutionPtr) currentClient->resolutions;
161    } else {
162	*num = num_resolutions;
163	return default_resolutions;
164    }
165}
166
167int
168GetDefaultPointSize(void)
169{
170    FontResolutionPtr res;
171    int         num;
172
173    res = GetClientResolutions(&num);
174    if (res)
175	return res->point_size;
176    else
177	return default_point_size;
178}
179
180int
181strncmpnocase(
182    const char *first,
183    const char *second,
184    int         n)
185{
186    register const unsigned char *ap,
187               *bp;
188
189    for (ap = (const unsigned char *) first,
190	    bp = (const unsigned char *) second;
191    /* SUPPRESS 112 */
192	    n > 0 && *ap && *bp; n--, ap++, bp++) {
193	register unsigned char a,
194	            b;
195
196	/* SUPPRESS 112 */
197	if ((a = *ap) != (b = *bp)) {
198	    /* try lowercasing and try again */
199
200	    if ((a >= XK_A) && (a <= XK_Z))
201		a += (XK_a - XK_A);
202	    else if ((a >= XK_Agrave) && (a <= XK_Odiaeresis))
203		a += (XK_agrave - XK_Agrave);
204	    else if ((a >= XK_Ooblique) && (a <= XK_Thorn))
205		a += (XK_oslash - XK_Ooblique);
206
207	    if ((b >= XK_A) && (b <= XK_Z))
208		b += (XK_a - XK_A);
209	    else if ((b >= XK_Agrave) && (b <= XK_Odiaeresis))
210		b += (XK_agrave - XK_Agrave);
211	    else if ((b >= XK_Ooblique) && (b <= XK_Thorn))
212		b += (XK_oslash - XK_Ooblique);
213
214	    if (a != b)
215		break;
216	}
217    }
218    /* SUPPRESS 112 */
219    return (n ? (((int) *ap) - ((int) *bp)) : 0);
220}
221
222/* block & wakeup handlers */
223
224typedef struct _BlockHandler {
225    FontBlockHandlerProcPtr	BlockHandler;
226    DifsWakeupFunc	WakeupHandler;
227    pointer     	blockData;
228    Bool        	deleted;
229}           BlockHandlerRec, *BlockHandlerPtr;
230
231static BlockHandlerPtr handlers;
232static int  numHandlers;
233static int  sizeHandlers;
234static Bool inHandler;
235static Bool handlerDeleted;
236
237/* called from the OS layer */
238void
239BlockHandler(
240    OSTimePtr   pTimeout,	/* DIX doesn't want to know how OS represents
241				 * time */
242    pointer     pReadmask)	/* nor how it represents the set of
243				 * descriptors */
244{
245    register int i,
246                j;
247
248    ++inHandler;
249    for (i = 0; i < numHandlers; i++)
250	(*handlers[i].BlockHandler) (handlers[i].blockData);
251    if (handlerDeleted) {
252	for (i = 0; i < numHandlers;)
253	    if (handlers[i].deleted) {
254		for (j = i; j < numHandlers - 1; j++)
255		    handlers[j] = handlers[j + 1];
256		numHandlers--;
257	    } else
258		i++;
259    }
260    --inHandler;
261}
262
263
264void
265WakeupHandler(
266    int		result,		/* result from the wait */
267    unsigned long * pReadmask)	/* the resulting descriptor mask */
268{
269    register int i,
270                j;
271
272    ++inHandler;
273    for (i = numHandlers - 1; i >= 0; i--)
274	(*handlers[i].WakeupHandler) (handlers[i].blockData,
275				      result, pReadmask);
276    if (handlerDeleted) {
277	for (i = 0; i < numHandlers;)
278	    if (handlers[i].deleted) {
279		for (j = i; j < numHandlers - 1; j++)
280		    handlers[j] = handlers[j + 1];
281		numHandlers--;
282	    } else
283		i++;
284    }
285    --inHandler;
286}
287
288/* Reentrant with BlockHandler and WakeupHandler, except wakeup won't
289 * get called until next time
290 */
291
292Bool
293RegisterBlockAndWakeupHandlers(
294    FontBlockHandlerProcPtr blockHandler,
295    DifsWakeupFunc wakeupHandler,
296    pointer     blockData)
297{
298    BlockHandlerPtr new;
299
300    if (numHandlers >= sizeHandlers) {
301	new = (BlockHandlerPtr) FSreallocarray(handlers, (numHandlers + 1),
302                                               sizeof(BlockHandlerRec));
303	if (!new)
304	    return FALSE;
305	handlers = new;
306	sizeHandlers = numHandlers + 1;
307    }
308    handlers[numHandlers].BlockHandler = blockHandler;
309    handlers[numHandlers].WakeupHandler = wakeupHandler;
310    handlers[numHandlers].blockData = blockData;
311    numHandlers = numHandlers + 1;
312    return TRUE;
313}
314
315void
316RemoveBlockAndWakeupHandlers(
317    FontBlockHandlerProcPtr blockHandler,
318    DifsWakeupFunc wakeupHandler,
319    pointer     blockData)
320{
321    int         i;
322
323    for (i = 0; i < numHandlers; i++)
324	if (handlers[i].BlockHandler == blockHandler &&
325		handlers[i].WakeupHandler == wakeupHandler &&
326		handlers[i].blockData == blockData) {
327	    if (inHandler) {
328		handlerDeleted = TRUE;
329		handlers[i].deleted = TRUE;
330	    } else {
331		for (; i < numHandlers - 1; i++)
332		    handlers[i] = handlers[i + 1];
333		numHandlers--;
334	    }
335	    break;
336	}
337}
338
339void
340InitBlockAndWakeupHandlers(void)
341{
342    FSfree(handlers);
343    handlers = (BlockHandlerPtr) 0;
344    numHandlers = 0;
345    sizeHandlers = 0;
346}
347
348/*
349 * A general work queue.  Perform some task before the server
350 * sleeps for input.
351 */
352
353WorkQueuePtr workQueue;
354static WorkQueuePtr *workQueueLast = &workQueue;
355
356/* ARGSUSED */
357void
358ProcessWorkQueue(void)
359{
360    WorkQueuePtr q,
361                n,
362                p;
363
364    p = NULL;
365    /*
366     * Scan the work queue once, calling each function.  Those which return
367     * TRUE are removed from the queue, otherwise they will be called again.
368     * This must be reentrant with QueueWorkProc, hence the crufty usage of
369     * variables.
370     */
371    for (q = workQueue; q; q = n) {
372	if ((*q->function) (q->client, q->closure)) {
373	    /* remove q from the list */
374	    n = q->next;	/* don't fetch until after func called */
375	    if (p)
376		p->next = n;
377	    else
378		workQueue = n;
379	    FSfree(q);
380	} else {
381	    n = q->next;	/* don't fetch until after func called */
382	    p = q;
383	}
384    }
385    if (p)
386	workQueueLast = &p->next;
387    else {
388	workQueueLast = &workQueue;
389    }
390}
391
392Bool
393QueueWorkProc(
394    Bool        (*function) (ClientPtr, pointer),
395    ClientPtr   client,
396    pointer     data)
397{
398    WorkQueuePtr q;
399
400    q = (WorkQueuePtr) FSalloc(sizeof *q);
401    if (!q)
402	return FALSE;
403    q->function = function;
404    q->client = client;
405    q->closure = data;
406    q->next = NULL;
407    *workQueueLast = q;
408    workQueueLast = &q->next;
409    return TRUE;
410}
411
412/*
413 * Manage a queue of sleeping clients, awakening them
414 * when requested, by using the OS functions IgnoreClient
415 * and AttendClient.  Note that this *ignores* the troubles
416 * with request data interleaving itself with events, but
417 * we'll leave that until a later time.
418 */
419
420typedef struct _SleepQueue {
421    struct _SleepQueue *next;
422    ClientPtr   client;
423    Bool        (*function) (ClientPtr, pointer);
424    pointer     closure;
425}           SleepQueueRec, *SleepQueuePtr;
426
427static SleepQueuePtr sleepQueue = NULL;
428
429Bool
430ClientSleep(
431    ClientPtr   client,
432    Bool        (*function) (ClientPtr, pointer),
433    pointer     data)
434{
435    SleepQueuePtr q;
436
437    q = (SleepQueuePtr) FSalloc(sizeof *q);
438    if (!q)
439	return FALSE;
440
441    IgnoreClient(client);
442    q->next = sleepQueue;
443    q->client = client;
444    q->function = function;
445    q->closure = data;
446    sleepQueue = q;
447    return TRUE;
448}
449
450Bool
451ClientSignal(ClientPtr client)
452{
453    SleepQueuePtr q;
454
455    for (q = sleepQueue; q; q = q->next)
456	if (q->client == client) {
457	    return QueueWorkProc(q->function, q->client, q->closure);
458	}
459    return FALSE;
460}
461
462void
463ClientWakeup(ClientPtr client)
464{
465    SleepQueuePtr q,
466               *prev;
467
468    prev = &sleepQueue;
469    while ((q = *prev) != (SleepQueuePtr) 0) {
470	if (q->client == client) {
471	    *prev = q->next;
472	    FSfree(q);
473	    if (client->clientGone == CLIENT_GONE)
474		CloseDownClient(client);
475	    else
476		AttendClient(client);
477	    break;
478	}
479	prev = &q->next;
480    }
481}
482
483Bool
484ClientIsAsleep(ClientPtr client)
485{
486    SleepQueuePtr q;
487
488    for (q = sleepQueue; q; q = q->next)
489	if (q->client == client)
490	    return TRUE;
491    return FALSE;
492}
493
494pointer
495Xalloc(unsigned long m)
496{
497    return FSalloc(m);
498}
499
500pointer
501Xrealloc(pointer n, unsigned long m)
502{
503    return FSrealloc(n, m);
504}
505
506void
507Xfree(unsigned long *n)
508{
509    FSfree(n);
510}
511
512pointer
513Xcalloc(unsigned long n)
514{
515    return FScalloc(1, n);
516}
517
518int
519set_font_authorizations(char **authorizations, int *authlen, void *_client)
520{
521    ClientPtr client = _client;
522#define AUTH1_NAME "hp-hostname-1"
523#define AUTH2_NAME "hp-printername-1"
524    static char result[1024];
525    char *p;
526    AuthContextPtr acp = client->auth;
527    int len1, len2;
528
529    if (acp != NULL && acp->authname != NULL && acp->authdata != NULL &&
530	(!strcmp(AUTH1_NAME, acp->authname) ||
531	 !strcmp(AUTH2_NAME, acp->authname)) &&
532	(len1 = strlen(acp->authname) + 1) +
533	(len2 = strlen(acp->authdata) + 1) + 2 * sizeof(short) <= 1024)
534    {
535	p = result;
536	*p++ = len1 >> 8;
537	*p++ = len1 &0xff;
538	*p++ = len2 >> 8;
539	*p++ = len2 & 0xff;
540	memmove( p, acp->authname, len1);
541	p += len1;
542	memmove( p, acp->authdata, len2);
543	p += len2;
544	*authlen = p - result;
545	*authorizations = result;
546	return 1;
547    }
548
549    *authlen = 0;
550    return 0;
551}
552
553int
554client_auth_generation(ClientPtr client)
555{
556    return client->auth_generation;
557}
558