Upgrade libgit2
[TortoiseGit.git] / src / TortoisePlink / x11disp.c
blobba3cff380c223c15af8c7d481f4c165ada7635a2
1 /*
2 * Functions to manage an X11Display structure, by creating one from
3 * an ordinary display name string, and freeing one.
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <time.h>
11 #include "putty.h"
12 #include "ssh.h"
13 #include "ssh/channel.h"
14 #include "tree234.h"
16 struct X11Display *x11_setup_display(const char *display, Conf *conf,
17 char **error_msg)
19 struct X11Display *disp = snew(struct X11Display);
20 char *localcopy;
22 *error_msg = NULL;
24 if (!display || !*display) {
25 localcopy = platform_get_x_display();
26 if (!localcopy || !*localcopy) {
27 sfree(localcopy);
28 localcopy = dupstr(":0"); /* plausible default for any platform */
30 } else
31 localcopy = dupstr(display);
34 * Parse the display name.
36 * We expect this to have one of the following forms:
38 * - the standard X format which looks like
39 * [ [ protocol '/' ] host ] ':' displaynumber [ '.' screennumber ]
40 * (X11 also permits a double colon to indicate DECnet, but
41 * that's not our problem, thankfully!)
43 * - only seen in the wild on MacOS (so far): a pathname to a
44 * Unix-domain socket, which will typically and confusingly
45 * end in ":0", and which I'm currently distinguishing from
46 * the standard scheme by noting that it starts with '/'.
48 if (localcopy[0] == '/') {
49 disp->unixsocketpath = localcopy;
50 disp->unixdomain = true;
51 disp->hostname = NULL;
52 disp->displaynum = -1;
53 disp->screennum = 0;
54 disp->addr = NULL;
55 } else {
56 char *colon, *dot, *slash;
57 char *protocol, *hostname;
59 colon = host_strrchr(localcopy, ':');
60 if (!colon) {
61 *error_msg = dupprintf("display name '%s' has no ':number'"
62 " suffix", localcopy);
64 sfree(disp);
65 sfree(localcopy);
66 return NULL;
69 *colon++ = '\0';
70 dot = strchr(colon, '.');
71 if (dot)
72 *dot++ = '\0';
74 disp->displaynum = atoi(colon);
75 if (dot)
76 disp->screennum = atoi(dot);
77 else
78 disp->screennum = 0;
80 protocol = NULL;
81 hostname = localcopy;
82 if (colon > localcopy) {
83 slash = strchr(localcopy, '/');
84 if (slash) {
85 *slash++ = '\0';
86 protocol = localcopy;
87 hostname = slash;
91 disp->hostname = *hostname ? dupstr(hostname) : NULL;
93 if (protocol)
94 disp->unixdomain = (!strcmp(protocol, "local") ||
95 !strcmp(protocol, "unix"));
96 else if (!*hostname || !strcmp(hostname, "unix"))
97 disp->unixdomain = platform_uses_x11_unix_by_default;
98 else
99 disp->unixdomain = false;
101 if (!disp->hostname && !disp->unixdomain)
102 disp->hostname = dupstr("localhost");
104 disp->unixsocketpath = NULL;
105 disp->addr = NULL;
107 sfree(localcopy);
111 * Look up the display hostname, if we need to.
113 if (!disp->unixdomain) {
114 const char *err;
116 disp->port = 6000 + disp->displaynum;
117 disp->addr = name_lookup(disp->hostname, disp->port,
118 &disp->realhost, conf, ADDRTYPE_UNSPEC,
119 NULL, NULL);
121 if ((err = sk_addr_error(disp->addr)) != NULL) {
122 *error_msg = dupprintf("unable to resolve host name '%s' in "
123 "display name", disp->hostname);
125 sk_addr_free(disp->addr);
126 sfree(disp->hostname);
127 sfree(disp->unixsocketpath);
128 sfree(disp);
129 return NULL;
134 * Try upgrading an IP-style localhost display to a Unix-socket
135 * display (as the standard X connection libraries do).
137 if (!disp->unixdomain && sk_address_is_local(disp->addr)) {
138 SockAddr *ux = platform_get_x11_unix_address(NULL, disp->displaynum);
139 const char *err = sk_addr_error(ux);
140 if (!err) {
141 /* Create trial connection to see if there is a useful Unix-domain
142 * socket */
143 Socket *s = sk_new(sk_addr_dup(ux), 0, false, false,
144 false, false, nullplug);
145 err = sk_socket_error(s);
146 sk_close(s);
148 if (err) {
149 sk_addr_free(ux);
150 } else {
151 sk_addr_free(disp->addr);
152 disp->unixdomain = true;
153 disp->addr = ux;
154 /* Fill in the rest in a moment */
158 if (disp->unixdomain) {
159 if (!disp->addr)
160 disp->addr = platform_get_x11_unix_address(disp->unixsocketpath,
161 disp->displaynum);
162 if (disp->unixsocketpath)
163 disp->realhost = dupstr(disp->unixsocketpath);
164 else
165 disp->realhost = dupprintf("unix:%d", disp->displaynum);
166 disp->port = 0;
170 * Fetch the local authorisation details.
172 disp->localauthproto = X11_NO_AUTH;
173 disp->localauthdata = NULL;
174 disp->localauthdatalen = 0;
175 platform_get_x11_auth(disp, conf);
177 return disp;
180 void x11_free_display(struct X11Display *disp)
182 sfree(disp->hostname);
183 sfree(disp->unixsocketpath);
184 if (disp->localauthdata)
185 smemclr(disp->localauthdata, disp->localauthdatalen);
186 sfree(disp->localauthdata);
187 sk_addr_free(disp->addr);
188 sfree(disp);