blob: eef7c4b55a4d5cd2d2eb0bf1f160537efc56f45d [file] [log] [blame]
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18#include <stdio.h>
Pierre Ossman8a044ee2015-03-03 16:44:30 +010019#include <stdint.h>
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000020
21#define NEED_REPLIES
22#include <X11/Xlib.h>
23#include <X11/Xlibint.h>
24#define _VNCEXT_PROTO_
25#include "vncExt.h"
26
27static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e,
28 xEvent* w);
29static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e,
30 xEvent* w);
31static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e,
32 xEvent* w);
33
34static Bool extensionInited = False;
35static XExtCodes* codes = 0;
36
37static Bool checkExtension(Display* dpy)
38{
39 if (!extensionInited) {
40 extensionInited = True;
41 codes = XInitExtension(dpy, VNCEXTNAME);
42 if (!codes) return False;
43 XESetWireToEvent(dpy, codes->first_event + VncExtClientCutTextNotify,
44 XVncExtClientCutTextNotifyWireToEvent);
45 XESetWireToEvent(dpy, codes->first_event + VncExtSelectionChangeNotify,
46 XVncExtSelectionChangeNotifyWireToEvent);
47 XESetWireToEvent(dpy, codes->first_event + VncExtQueryConnectNotify,
48 XVncExtQueryConnectNotifyWireToEvent);
49 }
50 return codes != 0;
51}
52
53Bool XVncExtQueryExtension(Display* dpy, int* event_basep, int* error_basep)
54{
55 if (!checkExtension(dpy)) return False;
56 *event_basep = codes->first_event;
57 *error_basep = codes->first_error;
58 return True;
59}
60
61Bool XVncExtSetParam(Display* dpy, const char* param)
62{
63 xVncExtSetParamReq* req;
64 xVncExtSetParamReply rep;
65
66 int paramLen = strlen(param);
67 if (paramLen > 255) return False;
68 if (!checkExtension(dpy)) return False;
69
70 LockDisplay(dpy);
71 GetReq(VncExtSetParam, req);
72 req->reqType = codes->major_opcode;
73 req->vncExtReqType = X_VncExtSetParam;
74 req->length += (paramLen + 3) >> 2;
75 req->paramLen = paramLen;
76 Data(dpy, param, paramLen);
77 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
78 UnlockDisplay(dpy);
79 SyncHandle();
80 return False;
81 }
82 UnlockDisplay(dpy);
83 SyncHandle();
84 return rep.success;
85}
86
87Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len)
88{
89 xVncExtGetParamReq* req;
90 xVncExtGetParamReply rep;
91
92 int paramLen = strlen(param);
93 *value = 0;
94 *len = 0;
95 if (paramLen > 255) return False;
96 if (!checkExtension(dpy)) return False;
97
98 LockDisplay(dpy);
99 GetReq(VncExtGetParam, req);
100 req->reqType = codes->major_opcode;
101 req->vncExtReqType = X_VncExtGetParam;
102 req->length += (paramLen + 3) >> 2;
103 req->paramLen = paramLen;
104 Data(dpy, param, paramLen);
105 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
106 UnlockDisplay(dpy);
107 SyncHandle();
108 return False;
109 }
110 if (rep.success) {
111 *len = rep.valueLen;
112 *value = (char*) Xmalloc (*len+1);
Pierre Ossmane83b14a2014-10-10 13:32:31 +0200113 if (!*value) {
114 _XEatData(dpy, (*len+1)&~1);
115 return False;
116 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000117 _XReadPad(dpy, *value, *len);
118 (*value)[*len] = 0;
119 }
120 UnlockDisplay(dpy);
121 SyncHandle();
122 return rep.success;
123}
124
125char* XVncExtGetParamDesc(Display* dpy, const char* param)
126{
127 xVncExtGetParamDescReq* req;
128 xVncExtGetParamDescReply rep;
129 char* desc = 0;
130
131 int paramLen = strlen(param);
132 if (paramLen > 255) return False;
133 if (!checkExtension(dpy)) return False;
134
135 LockDisplay(dpy);
136 GetReq(VncExtGetParamDesc, req);
137 req->reqType = codes->major_opcode;
138 req->vncExtReqType = X_VncExtGetParamDesc;
139 req->length += (paramLen + 3) >> 2;
140 req->paramLen = paramLen;
141 Data(dpy, param, paramLen);
142 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
143 UnlockDisplay(dpy);
144 SyncHandle();
145 return False;
146 }
147 if (rep.success) {
148 desc = (char*)Xmalloc(rep.descLen+1);
Pierre Ossmane83b14a2014-10-10 13:32:31 +0200149 if (!*desc) {
150 _XEatData(dpy, (rep.descLen+1)&~1);
151 return False;
152 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000153 _XReadPad(dpy, desc, rep.descLen);
154 desc[rep.descLen] = 0;
155 }
156 UnlockDisplay(dpy);
157 SyncHandle();
158 return desc;
159}
160
161char** XVncExtListParams(Display* dpy, int* nParams)
162{
163 xVncExtListParamsReq* req;
164 xVncExtListParamsReply rep;
165 char** list = 0;
166 char* ch;
167 int rlen, paramLen, i;
168
169 if (!checkExtension(dpy)) return False;
170
171 LockDisplay(dpy);
172 GetReq(VncExtListParams, req);
173 req->reqType = codes->major_opcode;
174 req->vncExtReqType = X_VncExtListParams;
175 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
176 UnlockDisplay(dpy);
177 SyncHandle();
178 return False;
179 }
180 UnlockDisplay(dpy);
181 SyncHandle();
182 if (rep.nParams) {
183 list = (char**)Xmalloc(rep.nParams * sizeof(char*));
184 rlen = rep.length << 2;
185 ch = (char*)Xmalloc(rlen + 1);
186 if (!list || !ch) {
187 if (list) Xfree((char*)list);
188 if (ch) Xfree(ch);
189 _XEatData(dpy, rlen);
190 UnlockDisplay(dpy);
191 SyncHandle();
192 return 0;
193 }
194 _XReadPad(dpy, ch, rlen);
195 paramLen = *ch++;
196 for (i = 0; i < rep.nParams; i++) {
197 list[i] = ch;
198 ch += paramLen;
199 paramLen = *ch;
200 *ch++ = 0;
201 }
202 }
203 *nParams = rep.nParams;
204 UnlockDisplay(dpy);
205 SyncHandle();
206 return list;
207}
208
209void XVncExtFreeParamList(char** list)
210{
211 if (list) {
212 Xfree(list[0]-1);
213 Xfree((char*)list);
214 }
215}
216
217Bool XVncExtSetServerCutText(Display* dpy, const char* str, int len)
218{
219 xVncExtSetServerCutTextReq* req;
220
221 if (!checkExtension(dpy)) return False;
222
223 LockDisplay(dpy);
224 GetReq(VncExtSetServerCutText, req);
225 req->reqType = codes->major_opcode;
226 req->vncExtReqType = X_VncExtSetServerCutText;
227 req->length += (len + 3) >> 2;
228 req->textLen = len;
229 Data(dpy, str, len);
230 UnlockDisplay(dpy);
231 SyncHandle();
232 return True;
233}
234
235Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len)
236{
237 xVncExtGetClientCutTextReq* req;
238 xVncExtGetClientCutTextReply rep;
239
240 if (!checkExtension(dpy)) return False;
241
242 LockDisplay(dpy);
243 GetReq(VncExtGetClientCutText, req);
244 req->reqType = codes->major_opcode;
245 req->vncExtReqType = X_VncExtGetClientCutText;
246 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
247 UnlockDisplay(dpy);
248 SyncHandle();
249 return False;
250 }
251 UnlockDisplay(dpy);
252 SyncHandle();
253 *len = rep.textLen;
254 *str = (char*) Xmalloc (*len+1);
Pierre Ossmane83b14a2014-10-10 13:32:31 +0200255 if (!*str) {
256 _XEatData(dpy, (*len+1)&~1);
257 return False;
258 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000259 _XReadPad(dpy, *str, *len);
260 (*str)[*len] = 0;
261 return True;
262}
263
264Bool XVncExtSelectInput(Display* dpy, Window w, int mask)
265{
266 xVncExtSelectInputReq* req;
267
268 if (!checkExtension(dpy)) return False;
269
270 LockDisplay(dpy);
271 GetReq(VncExtSelectInput, req);
272 req->reqType = codes->major_opcode;
273 req->vncExtReqType = X_VncExtSelectInput;
274 req->window = w;
275 req->mask = mask;
276 UnlockDisplay(dpy);
277 SyncHandle();
278 return True;
279}
280
281Bool XVncExtConnect(Display* dpy, char* hostAndPort)
282{
283 xVncExtConnectReq* req;
284 xVncExtConnectReply rep;
285
286 int strLen = strlen(hostAndPort);
287 if (strLen > 255) return False;
288 if (!checkExtension(dpy)) return False;
289
290 LockDisplay(dpy);
291 GetReq(VncExtConnect, req);
292 req->reqType = codes->major_opcode;
293 req->vncExtReqType = X_VncExtConnect;
294 req->length += (strLen + 3) >> 2;
295 req->strLen = strLen;
296 Data(dpy, hostAndPort, strLen);
297 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
298 UnlockDisplay(dpy);
299 SyncHandle();
300 return False;
301 }
302 UnlockDisplay(dpy);
303 SyncHandle();
304 return rep.success;
305}
306
307Bool XVncExtGetQueryConnect(Display* dpy, char** addr, char** user,
308 int* timeout, void** opaqueId)
309{
310 xVncExtGetQueryConnectReq* req;
311 xVncExtGetQueryConnectReply rep;
312
313 if (!checkExtension(dpy)) return False;
314
315 LockDisplay(dpy);
316 GetReq(VncExtGetQueryConnect, req);
317 req->reqType = codes->major_opcode;
318 req->vncExtReqType = X_VncExtGetQueryConnect;
319 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
320 UnlockDisplay(dpy);
321 SyncHandle();
322 return False;
323 }
324 UnlockDisplay(dpy);
325 SyncHandle();
326
327 *addr = Xmalloc(rep.addrLen+1);
Pierre Ossmane83b14a2014-10-10 13:32:31 +0200328 *user = Xmalloc(rep.userLen+1);
329 if (!*addr || !*user) {
330 Xfree(*addr);
331 Xfree(*user);
Pierre Ossman7728be22015-03-03 16:39:37 +0100332 _XEatData(dpy, ((rep.addrLen+1)&~1) + ((rep.userLen+1)&~1));
Pierre Ossmane83b14a2014-10-10 13:32:31 +0200333 return False;
334 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000335 _XReadPad(dpy, *addr, rep.addrLen);
336 (*addr)[rep.addrLen] = 0;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000337 _XReadPad(dpy, *user, rep.userLen);
338 (*user)[rep.userLen] = 0;
339 *timeout = rep.timeout;
Pierre Ossman8a044ee2015-03-03 16:44:30 +0100340 *opaqueId = (void*)(intptr_t)rep.opaqueId;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000341 return True;
342}
343
344Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve)
345{
346 xVncExtApproveConnectReq* req;
347
348 if (!checkExtension(dpy)) return False;
349
350 LockDisplay(dpy);
351 GetReq(VncExtApproveConnect, req);
352 req->reqType = codes->major_opcode;
353 req->vncExtReqType = X_VncExtApproveConnect;
354 req->approve = approve;
Pierre Ossman8a044ee2015-03-03 16:44:30 +0100355 req->opaqueId = (CARD32)(intptr_t)opaqueId;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000356 UnlockDisplay(dpy);
357 SyncHandle();
358 return True;
359}
360
361
362static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e,
363 xEvent* w)
364{
365 XVncExtClientCutTextEvent* ev = (XVncExtClientCutTextEvent*)e;
366 xVncExtClientCutTextNotifyEvent* wire = (xVncExtClientCutTextNotifyEvent*)w;
367 ev->type = wire->type & 0x7f;
368 ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
369 ev->send_event = (wire->type & 0x80) != 0;
370 ev->display = dpy;
371 ev->window = wire->window;
372 ev->time = wire->time;
373 return True;
374}
375
376static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e,
377 xEvent* w)
378{
379 XVncExtSelectionChangeEvent* ev = (XVncExtSelectionChangeEvent*)e;
380 xVncExtSelectionChangeNotifyEvent* wire
381 = (xVncExtSelectionChangeNotifyEvent*)w;
382 ev->type = wire->type & 0x7f;
383 ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
384 ev->send_event = (wire->type & 0x80) != 0;
385 ev->display = dpy;
386 ev->window = wire->window;
387 ev->selection = wire->selection;
388 return True;
389}
390
391static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e,
392 xEvent* w)
393{
394 XVncExtQueryConnectEvent* ev = (XVncExtQueryConnectEvent*)e;
395 xVncExtQueryConnectNotifyEvent* wire
396 = (xVncExtQueryConnectNotifyEvent*)w;
397 ev->type = wire->type & 0x7f;
398 ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
399 ev->send_event = (wire->type & 0x80) != 0;
400 ev->display = dpy;
401 ev->window = wire->window;
402 return True;
403}