1/******************************************************************************
2
3
4Copyright 1993, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26Author: Ralph Mor, X Consortium
27******************************************************************************/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <X11/ICE/ICElib.h>
33#include "ICElibint.h"
34
35
36IceProtocolSetupStatus
37IceProtocolSetup (
38	IceConn	   iceConn,
39	int 	   myOpcode,
40	IcePointer clientData,
41	Bool       mustAuthenticate,
42	int	   *majorVersionRet,
43	int	   *minorVersionRet,
44	char	   **vendorRet,
45	char	   **releaseRet,
46	int  	   errorLength,
47	char 	   *errorStringRet
48)
49{
50    iceProtocolSetupMsg	*pMsg;
51    char		*pData;
52    _IceProtocol	*myProtocol;
53    int			extra;
54    Bool		gotReply, ioErrorOccured;
55    int			accepted, i;
56    int			hisOpcode;
57    unsigned long	setup_sequence;
58    IceReplyWaitInfo 	replyWait;
59    _IceReply		reply;
60    IcePoVersionRec	*versionRec = NULL;
61    int			authCount;
62    int			*authIndices;
63
64    if (errorStringRet && errorLength > 0)
65	*errorStringRet = '\0';
66
67    *majorVersionRet = 0;
68    *minorVersionRet = 0;
69    *vendorRet = NULL;
70    *releaseRet = NULL;
71
72    if (myOpcode < 1 || myOpcode > _IceLastMajorOpcode)
73    {
74	if (errorStringRet && errorLength > 0) {
75	    strncpy (errorStringRet, "myOpcode out of range", errorLength);
76	    errorStringRet[errorLength - 1] = '\0';
77	}
78	return (IceProtocolSetupFailure);
79    }
80
81    myProtocol = &_IceProtocols[myOpcode - 1];
82
83    if (myProtocol->orig_client == NULL)
84    {
85	if (errorStringRet && errorLength > 0) {
86	    strncpy (errorStringRet,
87		"IceRegisterForProtocolSetup was not called", errorLength);
88	    errorStringRet[errorLength - 1] = '\0';
89	}
90	return (IceProtocolSetupFailure);
91    }
92
93
94    /*
95     * Make sure this protocol hasn't been activated already.
96     */
97
98    if (iceConn->process_msg_info)
99    {
100	for (i = iceConn->his_min_opcode; i <= iceConn->his_max_opcode; i++)
101	{
102	    if (iceConn->process_msg_info[
103		i - iceConn->his_min_opcode].in_use &&
104                iceConn->process_msg_info[
105		i - iceConn->his_min_opcode ].my_opcode == myOpcode)
106		break;
107	}
108
109	if (i <= iceConn->his_max_opcode)
110	{
111	    return (IceProtocolAlreadyActive);
112	}
113    }
114
115    /*
116     * Generate the message.
117     */
118
119    if (myProtocol->orig_client->auth_count > 0)
120    {
121	authIndices = malloc (
122	    myProtocol->orig_client->auth_count * sizeof (int));
123
124	if (authIndices == NULL)
125	{
126	    if (errorStringRet && errorLength > 0) {
127		strncpy (errorStringRet,
128			 "malloc of authIndices failed", errorLength);
129		errorStringRet[errorLength - 1] = '\0';
130	    }
131	    return (IceProtocolSetupFailure);
132	}
133
134	_IceGetPoValidAuthIndices (myProtocol->protocol_name,
135	    iceConn->connection_string,
136	    myProtocol->orig_client->auth_count,
137	    (const char **) myProtocol->orig_client->auth_names,
138            &authCount, authIndices);
139
140    }
141    else
142    {
143	authCount = 0;
144	authIndices = NULL;
145    }
146
147    extra = STRING_BYTES (myProtocol->protocol_name) +
148            STRING_BYTES (myProtocol->orig_client->vendor) +
149            STRING_BYTES (myProtocol->orig_client->release);
150
151    for (i = 0; i < authCount; i++)
152    {
153	extra += STRING_BYTES (myProtocol->orig_client->auth_names[
154	    authIndices[i]]);
155    }
156
157    extra += (myProtocol->orig_client->version_count * 4);
158
159    IceGetHeaderExtra (iceConn, 0, ICE_ProtocolSetup,
160	SIZEOF (iceProtocolSetupMsg), WORD64COUNT (extra),
161	iceProtocolSetupMsg, pMsg, pData);
162
163    if (pData == NULL) {
164	iceConn->outbufptr -= SIZEOF (iceProtocolSetupMsg);
165	free(authIndices);
166	if (errorStringRet && errorLength > 0) {
167	    strncpy (errorStringRet,
168		"Too much extra data for iceProtocolSetupMsg", errorLength);
169	    errorStringRet[errorLength - 1] = '\0';
170	}
171	return (IceProtocolSetupFailure);
172    }
173
174    setup_sequence = iceConn->send_sequence;
175
176    pMsg->protocolOpcode = myOpcode;
177    pMsg->versionCount = myProtocol->orig_client->version_count;
178    pMsg->authCount = authCount;
179    pMsg->mustAuthenticate = mustAuthenticate;
180
181    STORE_STRING (pData, myProtocol->protocol_name);
182    STORE_STRING (pData, myProtocol->orig_client->vendor);
183    STORE_STRING (pData, myProtocol->orig_client->release);
184
185    for (i = 0; i < authCount; i++)
186    {
187	STORE_STRING (pData, myProtocol->orig_client->auth_names[
188	    authIndices[i]]);
189    }
190
191    for (i = 0; i < myProtocol->orig_client->version_count; i++)
192    {
193	STORE_CARD16 (pData,
194	    myProtocol->orig_client->version_recs[i].major_version);
195	STORE_CARD16 (pData,
196	    myProtocol->orig_client->version_recs[i].minor_version);
197    }
198
199    IceFlush (iceConn);
200
201
202    /*
203     * Process messages until we get a Protocol Reply.
204     */
205
206    replyWait.sequence_of_request = setup_sequence;
207    replyWait.major_opcode_of_request = 0;
208    replyWait.minor_opcode_of_request = ICE_ProtocolSetup;
209    replyWait.reply = (IcePointer) &reply;
210
211    iceConn->protosetup_to_you = malloc (sizeof (_IceProtoSetupToYouInfo));
212    iceConn->protosetup_to_you->my_opcode = myOpcode;
213    iceConn->protosetup_to_you->my_auth_count = authCount;
214    iceConn->protosetup_to_you->auth_active = 0;
215    iceConn->protosetup_to_you->my_auth_indices = authIndices;
216
217    gotReply = False;
218    ioErrorOccured = False;
219    accepted = 0;
220
221    while (!gotReply && !ioErrorOccured)
222    {
223	ioErrorOccured = (IceProcessMessages (
224	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
225
226	if (ioErrorOccured)
227	{
228	    if (errorStringRet && errorLength > 0) {
229		strncpy (errorStringRet,
230		    "IO error occurred doing Protocol Setup on connection",
231		    errorLength);
232		errorStringRet[errorLength - 1] = '\0';
233	    }
234	    return (IceProtocolSetupIOError);
235	}
236	else if (gotReply)
237	{
238	    if (reply.type == ICE_PROTOCOL_REPLY)
239	    {
240		if (reply.protocol_reply.version_index >=
241		    myProtocol->orig_client->version_count)
242		{
243		    if (errorStringRet && errorLength > 0) {
244			strncpy (errorStringRet,
245	                    "Got a bad version index in the Protocol Reply",
246		            errorLength);
247			errorStringRet[errorLength - 1] = '\0';
248		    }
249
250		    free (reply.protocol_reply.vendor);
251		    free (reply.protocol_reply.release);
252		}
253		else
254		{
255		    versionRec = &(myProtocol->orig_client->version_recs[
256		        reply.protocol_reply.version_index]);
257
258		    accepted = 1;
259		}
260	    }
261	    else /* reply.type == ICE_PROTOCOL_ERROR */
262	    {
263		/* Protocol Setup failed */
264
265		if (errorStringRet && errorLength > 0) {
266		    strncpy (errorStringRet, reply.protocol_error.error_message,
267			errorLength);
268		    errorStringRet[errorLength - 1] = '\0';
269		}
270
271		free (reply.protocol_error.error_message);
272	    }
273
274	    if (iceConn->protosetup_to_you->my_auth_indices)
275		free (iceConn->protosetup_to_you->my_auth_indices);
276	    free (iceConn->protosetup_to_you);
277	    iceConn->protosetup_to_you = NULL;
278	}
279    }
280
281    if (accepted)
282    {
283	_IceProcessMsgInfo *process_msg_info;
284
285	*majorVersionRet = versionRec->major_version;
286	*minorVersionRet = versionRec->minor_version;
287	*vendorRet = reply.protocol_reply.vendor;
288	*releaseRet = reply.protocol_reply.release;
289
290
291	/*
292	 * Increase the reference count for the number of active protocols.
293	 */
294
295	iceConn->proto_ref_count++;
296
297
298	/*
299	 * We may be using a different major opcode for this protocol
300	 * than the other client.  Whenever we get a message, we must
301	 * map to our own major opcode.
302	 */
303
304	hisOpcode = reply.protocol_reply.major_opcode;
305
306	_IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
307
308	process_msg_info = &iceConn->process_msg_info[hisOpcode -
309	    iceConn->his_min_opcode];
310
311	process_msg_info->client_data = clientData;
312	process_msg_info->accept_flag = 0;
313
314	process_msg_info->process_msg_proc.orig_client =
315		versionRec->process_msg_proc;
316
317	return (IceProtocolSetupSuccess);
318    }
319    else
320    {
321	return (IceProtocolSetupFailure);
322    }
323}
324