1266e564dSmrg/******************************************************************************
2266e564dSmrg
3266e564dSmrg
4266e564dSmrgCopyright 1993, 1998  The Open Group
5266e564dSmrg
6266e564dSmrgPermission to use, copy, modify, distribute, and sell this software and its
7266e564dSmrgdocumentation for any purpose is hereby granted without fee, provided that
8266e564dSmrgthe above copyright notice appear in all copies and that both that
9266e564dSmrgcopyright notice and this permission notice appear in supporting
10266e564dSmrgdocumentation.
11266e564dSmrg
12266e564dSmrgThe above copyright notice and this permission notice shall be included in
13266e564dSmrgall copies or substantial portions of the Software.
14266e564dSmrg
15266e564dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16266e564dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17266e564dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18266e564dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19266e564dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20266e564dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21266e564dSmrg
22266e564dSmrgExcept as contained in this notice, the name of The Open Group shall not be
23266e564dSmrgused in advertising or otherwise to promote the sale, use or other dealings
24266e564dSmrgin this Software without prior written authorization from The Open Group.
25266e564dSmrg
26266e564dSmrgAuthor: Ralph Mor, X Consortium
27266e564dSmrg******************************************************************************/
28266e564dSmrg
29266e564dSmrg#ifdef HAVE_CONFIG_H
30266e564dSmrg#include <config.h>
31266e564dSmrg#endif
32266e564dSmrg#include <X11/ICE/ICElib.h>
33266e564dSmrg#include "ICElibint.h"
34266e564dSmrg
35266e564dSmrg
36266e564dSmrgIceProtocolSetupStatus
37c5629e66SmrgIceProtocolSetup (
38c5629e66Smrg	IceConn	   iceConn,
39c5629e66Smrg	int 	   myOpcode,
40c5629e66Smrg	IcePointer clientData,
41c5629e66Smrg	Bool       mustAuthenticate,
42c5629e66Smrg	int	   *majorVersionRet,
43c5629e66Smrg	int	   *minorVersionRet,
44c5629e66Smrg	char	   **vendorRet,
45c5629e66Smrg	char	   **releaseRet,
46c5629e66Smrg	int  	   errorLength,
47c5629e66Smrg	char 	   *errorStringRet
48c5629e66Smrg)
49266e564dSmrg{
50266e564dSmrg    iceProtocolSetupMsg	*pMsg;
51266e564dSmrg    char		*pData;
52266e564dSmrg    _IceProtocol	*myProtocol;
53266e564dSmrg    int			extra;
54266e564dSmrg    Bool		gotReply, ioErrorOccured;
55266e564dSmrg    int			accepted, i;
56266e564dSmrg    int			hisOpcode;
57266e564dSmrg    unsigned long	setup_sequence;
58266e564dSmrg    IceReplyWaitInfo 	replyWait;
59266e564dSmrg    _IceReply		reply;
60266e564dSmrg    IcePoVersionRec	*versionRec = NULL;
61266e564dSmrg    int			authCount;
62266e564dSmrg    int			*authIndices;
63266e564dSmrg
64266e564dSmrg    if (errorStringRet && errorLength > 0)
65266e564dSmrg	*errorStringRet = '\0';
66266e564dSmrg
67266e564dSmrg    *majorVersionRet = 0;
68266e564dSmrg    *minorVersionRet = 0;
69266e564dSmrg    *vendorRet = NULL;
70266e564dSmrg    *releaseRet = NULL;
71266e564dSmrg
72266e564dSmrg    if (myOpcode < 1 || myOpcode > _IceLastMajorOpcode)
73266e564dSmrg    {
74a3129944Smrg	if (errorStringRet && errorLength > 0) {
75a3129944Smrg	    strncpy (errorStringRet, "myOpcode out of range", errorLength);
76a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
77a3129944Smrg	}
78266e564dSmrg	return (IceProtocolSetupFailure);
79266e564dSmrg    }
80266e564dSmrg
81266e564dSmrg    myProtocol = &_IceProtocols[myOpcode - 1];
82266e564dSmrg
83266e564dSmrg    if (myProtocol->orig_client == NULL)
84266e564dSmrg    {
85a3129944Smrg	if (errorStringRet && errorLength > 0) {
86a3129944Smrg	    strncpy (errorStringRet,
87a3129944Smrg		"IceRegisterForProtocolSetup was not called", errorLength);
88a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
89a3129944Smrg	}
90266e564dSmrg	return (IceProtocolSetupFailure);
91266e564dSmrg    }
92266e564dSmrg
93266e564dSmrg
94266e564dSmrg    /*
95266e564dSmrg     * Make sure this protocol hasn't been activated already.
96266e564dSmrg     */
97266e564dSmrg
98266e564dSmrg    if (iceConn->process_msg_info)
99266e564dSmrg    {
100266e564dSmrg	for (i = iceConn->his_min_opcode; i <= iceConn->his_max_opcode; i++)
101266e564dSmrg	{
102266e564dSmrg	    if (iceConn->process_msg_info[
103266e564dSmrg		i - iceConn->his_min_opcode].in_use &&
104266e564dSmrg                iceConn->process_msg_info[
105266e564dSmrg		i - iceConn->his_min_opcode ].my_opcode == myOpcode)
106266e564dSmrg		break;
107266e564dSmrg	}
108266e564dSmrg
109266e564dSmrg	if (i <= iceConn->his_max_opcode)
110266e564dSmrg	{
111266e564dSmrg	    return (IceProtocolAlreadyActive);
112266e564dSmrg	}
113266e564dSmrg    }
114266e564dSmrg
115266e564dSmrg    /*
116266e564dSmrg     * Generate the message.
117266e564dSmrg     */
118266e564dSmrg
119266e564dSmrg    if (myProtocol->orig_client->auth_count > 0)
120266e564dSmrg    {
121fb5e8d76Smrg	authIndices = malloc (
122266e564dSmrg	    myProtocol->orig_client->auth_count * sizeof (int));
123266e564dSmrg
1243bf3b463Smrg	if (authIndices == NULL)
1253bf3b463Smrg	{
1263bf3b463Smrg	    if (errorStringRet && errorLength > 0) {
1273bf3b463Smrg		strncpy (errorStringRet,
1283bf3b463Smrg			 "malloc of authIndices failed", errorLength);
1293bf3b463Smrg		errorStringRet[errorLength - 1] = '\0';
1303bf3b463Smrg	    }
1313bf3b463Smrg	    return (IceProtocolSetupFailure);
1323bf3b463Smrg	}
1333bf3b463Smrg
134266e564dSmrg	_IceGetPoValidAuthIndices (myProtocol->protocol_name,
135266e564dSmrg	    iceConn->connection_string,
136266e564dSmrg	    myProtocol->orig_client->auth_count,
1379ef0b394Smrg	    (const char **) myProtocol->orig_client->auth_names,
138266e564dSmrg            &authCount, authIndices);
139266e564dSmrg
140266e564dSmrg    }
141266e564dSmrg    else
142266e564dSmrg    {
143266e564dSmrg	authCount = 0;
144266e564dSmrg	authIndices = NULL;
145266e564dSmrg    }
146266e564dSmrg
147266e564dSmrg    extra = STRING_BYTES (myProtocol->protocol_name) +
148266e564dSmrg            STRING_BYTES (myProtocol->orig_client->vendor) +
149266e564dSmrg            STRING_BYTES (myProtocol->orig_client->release);
150266e564dSmrg
151266e564dSmrg    for (i = 0; i < authCount; i++)
152266e564dSmrg    {
153266e564dSmrg	extra += STRING_BYTES (myProtocol->orig_client->auth_names[
154266e564dSmrg	    authIndices[i]]);
155266e564dSmrg    }
156266e564dSmrg
157266e564dSmrg    extra += (myProtocol->orig_client->version_count * 4);
158266e564dSmrg
159266e564dSmrg    IceGetHeaderExtra (iceConn, 0, ICE_ProtocolSetup,
160266e564dSmrg	SIZEOF (iceProtocolSetupMsg), WORD64COUNT (extra),
161266e564dSmrg	iceProtocolSetupMsg, pMsg, pData);
162266e564dSmrg
1631009a292Smrg    if (pData == NULL) {
1641009a292Smrg	iceConn->outbufptr -= SIZEOF (iceProtocolSetupMsg);
1651009a292Smrg	free(authIndices);
1661009a292Smrg	if (errorStringRet && errorLength > 0) {
1671009a292Smrg	    strncpy (errorStringRet,
1681009a292Smrg		"Too much extra data for iceProtocolSetupMsg", errorLength);
1691009a292Smrg	    errorStringRet[errorLength - 1] = '\0';
1701009a292Smrg	}
1711009a292Smrg	return (IceProtocolSetupFailure);
1721009a292Smrg    }
1731009a292Smrg
174266e564dSmrg    setup_sequence = iceConn->send_sequence;
175266e564dSmrg
176266e564dSmrg    pMsg->protocolOpcode = myOpcode;
177266e564dSmrg    pMsg->versionCount = myProtocol->orig_client->version_count;
178266e564dSmrg    pMsg->authCount = authCount;
179266e564dSmrg    pMsg->mustAuthenticate = mustAuthenticate;
180266e564dSmrg
181266e564dSmrg    STORE_STRING (pData, myProtocol->protocol_name);
182266e564dSmrg    STORE_STRING (pData, myProtocol->orig_client->vendor);
183266e564dSmrg    STORE_STRING (pData, myProtocol->orig_client->release);
184266e564dSmrg
185266e564dSmrg    for (i = 0; i < authCount; i++)
186266e564dSmrg    {
187266e564dSmrg	STORE_STRING (pData, myProtocol->orig_client->auth_names[
188266e564dSmrg	    authIndices[i]]);
189266e564dSmrg    }
190266e564dSmrg
191266e564dSmrg    for (i = 0; i < myProtocol->orig_client->version_count; i++)
192266e564dSmrg    {
193266e564dSmrg	STORE_CARD16 (pData,
194266e564dSmrg	    myProtocol->orig_client->version_recs[i].major_version);
195266e564dSmrg	STORE_CARD16 (pData,
196266e564dSmrg	    myProtocol->orig_client->version_recs[i].minor_version);
197266e564dSmrg    }
198266e564dSmrg
199266e564dSmrg    IceFlush (iceConn);
200266e564dSmrg
201266e564dSmrg
202266e564dSmrg    /*
203266e564dSmrg     * Process messages until we get a Protocol Reply.
204266e564dSmrg     */
205266e564dSmrg
206266e564dSmrg    replyWait.sequence_of_request = setup_sequence;
207266e564dSmrg    replyWait.major_opcode_of_request = 0;
208266e564dSmrg    replyWait.minor_opcode_of_request = ICE_ProtocolSetup;
209266e564dSmrg    replyWait.reply = (IcePointer) &reply;
210266e564dSmrg
211fb5e8d76Smrg    iceConn->protosetup_to_you = malloc (sizeof (_IceProtoSetupToYouInfo));
212266e564dSmrg    iceConn->protosetup_to_you->my_opcode = myOpcode;
213266e564dSmrg    iceConn->protosetup_to_you->my_auth_count = authCount;
214266e564dSmrg    iceConn->protosetup_to_you->auth_active = 0;
215266e564dSmrg    iceConn->protosetup_to_you->my_auth_indices = authIndices;
216266e564dSmrg
217266e564dSmrg    gotReply = False;
218266e564dSmrg    ioErrorOccured = False;
219266e564dSmrg    accepted = 0;
220266e564dSmrg
221266e564dSmrg    while (!gotReply && !ioErrorOccured)
222266e564dSmrg    {
223266e564dSmrg	ioErrorOccured = (IceProcessMessages (
224266e564dSmrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
225266e564dSmrg
226266e564dSmrg	if (ioErrorOccured)
227266e564dSmrg	{
228a3129944Smrg	    if (errorStringRet && errorLength > 0) {
229a3129944Smrg		strncpy (errorStringRet,
2301009a292Smrg		    "IO error occurred doing Protocol Setup on connection",
231a3129944Smrg		    errorLength);
232a3129944Smrg		errorStringRet[errorLength - 1] = '\0';
233a3129944Smrg	    }
234266e564dSmrg	    return (IceProtocolSetupIOError);
235266e564dSmrg	}
236266e564dSmrg	else if (gotReply)
237266e564dSmrg	{
238266e564dSmrg	    if (reply.type == ICE_PROTOCOL_REPLY)
239266e564dSmrg	    {
240266e564dSmrg		if (reply.protocol_reply.version_index >=
241266e564dSmrg		    myProtocol->orig_client->version_count)
242266e564dSmrg		{
243a3129944Smrg		    if (errorStringRet && errorLength > 0) {
244a3129944Smrg			strncpy (errorStringRet,
245a3129944Smrg	                    "Got a bad version index in the Protocol Reply",
246a3129944Smrg		            errorLength);
247a3129944Smrg			errorStringRet[errorLength - 1] = '\0';
248a3129944Smrg		    }
249266e564dSmrg
250266e564dSmrg		    free (reply.protocol_reply.vendor);
251266e564dSmrg		    free (reply.protocol_reply.release);
252266e564dSmrg		}
253266e564dSmrg		else
254266e564dSmrg		{
255266e564dSmrg		    versionRec = &(myProtocol->orig_client->version_recs[
256266e564dSmrg		        reply.protocol_reply.version_index]);
257266e564dSmrg
258266e564dSmrg		    accepted = 1;
259266e564dSmrg		}
260266e564dSmrg	    }
261266e564dSmrg	    else /* reply.type == ICE_PROTOCOL_ERROR */
262266e564dSmrg	    {
263266e564dSmrg		/* Protocol Setup failed */
2649ef0b394Smrg
265a3129944Smrg		if (errorStringRet && errorLength > 0) {
266a3129944Smrg		    strncpy (errorStringRet, reply.protocol_error.error_message,
267a3129944Smrg			errorLength);
268a3129944Smrg		    errorStringRet[errorLength - 1] = '\0';
269a3129944Smrg		}
270266e564dSmrg
271266e564dSmrg		free (reply.protocol_error.error_message);
272266e564dSmrg	    }
273266e564dSmrg
274266e564dSmrg	    if (iceConn->protosetup_to_you->my_auth_indices)
275fb5e8d76Smrg		free (iceConn->protosetup_to_you->my_auth_indices);
276fb5e8d76Smrg	    free (iceConn->protosetup_to_you);
277266e564dSmrg	    iceConn->protosetup_to_you = NULL;
278266e564dSmrg	}
279266e564dSmrg    }
280266e564dSmrg
281266e564dSmrg    if (accepted)
282266e564dSmrg    {
283266e564dSmrg	_IceProcessMsgInfo *process_msg_info;
284266e564dSmrg
285266e564dSmrg	*majorVersionRet = versionRec->major_version;
286266e564dSmrg	*minorVersionRet = versionRec->minor_version;
287266e564dSmrg	*vendorRet = reply.protocol_reply.vendor;
288266e564dSmrg	*releaseRet = reply.protocol_reply.release;
2899ef0b394Smrg
290266e564dSmrg
291266e564dSmrg	/*
292266e564dSmrg	 * Increase the reference count for the number of active protocols.
293266e564dSmrg	 */
294266e564dSmrg
295266e564dSmrg	iceConn->proto_ref_count++;
296266e564dSmrg
297266e564dSmrg
298266e564dSmrg	/*
299266e564dSmrg	 * We may be using a different major opcode for this protocol
300266e564dSmrg	 * than the other client.  Whenever we get a message, we must
301266e564dSmrg	 * map to our own major opcode.
302266e564dSmrg	 */
303266e564dSmrg
304266e564dSmrg	hisOpcode = reply.protocol_reply.major_opcode;
305266e564dSmrg
306266e564dSmrg	_IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
307266e564dSmrg
308266e564dSmrg	process_msg_info = &iceConn->process_msg_info[hisOpcode -
309266e564dSmrg	    iceConn->his_min_opcode];
310266e564dSmrg
311266e564dSmrg	process_msg_info->client_data = clientData;
312266e564dSmrg	process_msg_info->accept_flag = 0;
313266e564dSmrg
314266e564dSmrg	process_msg_info->process_msg_proc.orig_client =
315266e564dSmrg		versionRec->process_msg_proc;
316266e564dSmrg
317266e564dSmrg	return (IceProtocolSetupSuccess);
318266e564dSmrg    }
319266e564dSmrg    else
320266e564dSmrg    {
321266e564dSmrg	return (IceProtocolSetupFailure);
322266e564dSmrg    }
323266e564dSmrg}
324