setupapi: Add stubs for CM_Get_Device_IDA and CM_Get_Device_ID_Size.
[wine/hacks.git] / dlls / inetcomm / internettransport.c
bloba056201fc15eb53121e535e5b681be252ca6ee00
1 /*
2 * Internet Messaging Transport Base Class
4 * Copyright 2006 Robert Shearman for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winsock2.h"
30 #include "ws2tcpip.h"
32 #include "wine/debug.h"
34 #include "inetcomm_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
38 static const WCHAR wszClassName[] = {'T','h','o','r','C','o','n','n','W','n','d','C','l','a','s','s',0};
40 #define IX_READ (WM_USER + 0)
41 #define IX_READLINE (WM_USER + 1)
42 #define IX_WRITE (WM_USER + 2)
44 HRESULT InternetTransport_Init(InternetTransport *This)
46 This->pCallback = NULL;
47 This->Status = IXP_DISCONNECTED;
48 This->Socket = -1;
49 This->fCommandLogging = FALSE;
50 This->fnCompletion = NULL;
52 return S_OK;
55 HRESULT InternetTransport_GetServerInfo(InternetTransport *This, LPINETSERVER pInetServer)
57 if (This->Status == IXP_DISCONNECTED)
58 return IXP_E_NOT_CONNECTED;
60 memcpy(pInetServer, &This->ServerInfo, sizeof(*pInetServer));
61 return S_OK;
64 HRESULT InternetTransport_InetServerFromAccount(InternetTransport *This,
65 IImnAccount *pAccount, LPINETSERVER pInetServer)
67 FIXME("(%p, %p): stub\n", pAccount, pInetServer);
68 return E_NOTIMPL;
71 HRESULT InternetTransport_Connect(InternetTransport *This,
72 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
74 struct addrinfo *ai;
75 struct addrinfo *ai_cur;
76 struct addrinfo hints;
77 int ret;
78 char szPort[10];
80 if (This->Status != IXP_DISCONNECTED)
81 return IXP_E_ALREADY_CONNECTED;
83 memcpy(&This->ServerInfo, pInetServer, sizeof(This->ServerInfo));
84 This->fCommandLogging = fCommandLogging;
86 This->hwnd = CreateWindowW(wszClassName, wszClassName, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0);
87 if (!This->hwnd)
88 return HRESULT_FROM_WIN32(GetLastError());
89 SetWindowLongPtrW(This->hwnd, GWLP_USERDATA, (LONG_PTR)This);
91 hints.ai_flags = 0;
92 hints.ai_family = PF_UNSPEC;
93 hints.ai_socktype = SOCK_STREAM;
94 hints.ai_protocol = IPPROTO_TCP;
95 hints.ai_addrlen = 0;
96 hints.ai_addr = NULL;
97 hints.ai_canonname = NULL;
98 hints.ai_next = NULL;
100 snprintf(szPort, sizeof(szPort), "%d", (unsigned short)pInetServer->dwPort);
102 InternetTransport_ChangeStatus(This, IXP_FINDINGHOST);
104 ret = getaddrinfo(pInetServer->szServerName, szPort, &hints, &ai);
105 if (ret)
107 ERR("getaddrinfo failed: %d\n", ret);
108 return IXP_E_CANT_FIND_HOST;
111 for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
113 if (TRACE_ON(inetcomm))
115 char host[256];
116 char service[256];
117 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
118 host, sizeof(host), service, sizeof(service),
119 NI_NUMERICHOST | NI_NUMERICSERV);
120 TRACE("trying %s:%s\n", host, service);
123 InternetTransport_ChangeStatus(This, IXP_CONNECTING);
125 This->Socket = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
126 if (This->Socket < 0)
128 WARN("socket() failed\n");
129 continue;
132 /* FIXME: set to async */
134 if (0 > connect(This->Socket, ai_cur->ai_addr, ai_cur->ai_addrlen))
136 WARN("connect() failed\n");
137 closesocket(This->Socket);
138 continue;
140 InternetTransport_ChangeStatus(This, IXP_CONNECTED);
142 /* FIXME: call WSAAsyncSelect */
144 freeaddrinfo(ai);
145 TRACE("connected\n");
146 return S_OK;
149 freeaddrinfo(ai);
151 return IXP_E_CANT_FIND_HOST;
154 HRESULT InternetTransport_HandsOffCallback(InternetTransport *This)
156 if (!This->pCallback)
157 return S_FALSE;
159 ITransportCallback_Release(This->pCallback);
160 This->pCallback = NULL;
162 return S_OK;
165 HRESULT InternetTransport_DropConnection(InternetTransport *This)
167 int ret;
169 if (This->Status == IXP_DISCONNECTED)
170 return IXP_E_NOT_CONNECTED;
172 ret = shutdown(This->Socket, SD_BOTH);
174 ret = closesocket(This->Socket);
176 DestroyWindow(This->hwnd);
177 This->hwnd = NULL;
179 InternetTransport_ChangeStatus(This, IXP_DISCONNECTED);
181 return S_OK;
184 HRESULT InternetTransport_GetStatus(InternetTransport *This,
185 IXPSTATUS *pCurrentStatus)
187 *pCurrentStatus = This->Status;
188 return S_OK;
191 HRESULT InternetTransport_ChangeStatus(InternetTransport *This, IXPSTATUS Status)
193 This->Status = Status;
194 if (This->pCallback)
195 ITransportCallback_OnStatus(This->pCallback, Status,
196 (IInternetTransport *)&This->u.vtbl);
197 return S_OK;
200 HRESULT InternetTransport_Read(InternetTransport *This, int cbBuffer,
201 INETXPORT_COMPLETION_FUNCTION fnCompletion)
203 if (This->Status == IXP_DISCONNECTED)
204 return IXP_E_NOT_CONNECTED;
206 if (This->fnCompletion)
207 return IXP_E_BUSY;
209 This->fnCompletion = fnCompletion;
211 This->cbBuffer = cbBuffer;
212 This->pBuffer = HeapAlloc(GetProcessHeap(), 0, This->cbBuffer);
213 This->iCurrentBufferOffset = 0;
215 if (WSAAsyncSelect(This->Socket, This->hwnd, IX_READ, FD_READ) == SOCKET_ERROR)
217 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
218 /* FIXME: handle error */
220 return S_OK;
223 HRESULT InternetTransport_ReadLine(InternetTransport *This,
224 INETXPORT_COMPLETION_FUNCTION fnCompletion)
226 if (This->Status == IXP_DISCONNECTED)
227 return IXP_E_NOT_CONNECTED;
229 if (This->fnCompletion)
230 return IXP_E_BUSY;
232 This->fnCompletion = fnCompletion;
234 This->cbBuffer = 1024;
235 This->pBuffer = HeapAlloc(GetProcessHeap(), 0, This->cbBuffer);
236 This->iCurrentBufferOffset = 0;
238 if (WSAAsyncSelect(This->Socket, This->hwnd, IX_READLINE, FD_READ) == SOCKET_ERROR)
240 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
241 /* FIXME: handle error */
243 return S_OK;
246 HRESULT InternetTransport_Write(InternetTransport *This, const char *pvData,
247 int cbSize, INETXPORT_COMPLETION_FUNCTION fnCompletion)
249 int ret;
251 if (This->Status == IXP_DISCONNECTED)
252 return IXP_E_NOT_CONNECTED;
254 if (This->fnCompletion)
255 return IXP_E_BUSY;
257 /* FIXME: do this asynchronously */
258 ret = send(This->Socket, pvData, cbSize, 0);
259 if (ret == SOCKET_ERROR)
261 ERR("send failed with error %d\n", WSAGetLastError());
262 /* FIXME: handle error */
265 fnCompletion((IInternetTransport *)&This->u.vtbl, NULL, 0);
267 return S_OK;
270 static LRESULT CALLBACK InternetTransport_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
272 if (uMsg == IX_READ)
274 InternetTransport *This = (InternetTransport *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
276 /* no work to do */
277 if (!This->fnCompletion)
278 return 0;
280 while (This->iCurrentBufferOffset < This->cbBuffer)
282 if (recv(This->Socket, &This->pBuffer[This->iCurrentBufferOffset], 1, 0) <= 0)
284 if (WSAGetLastError() == WSAEWOULDBLOCK)
285 break;
287 ERR("recv failed with error %d\n", WSAGetLastError());
288 /* FIXME: handle error */
291 This->iCurrentBufferOffset++;
293 if (This->iCurrentBufferOffset == This->cbBuffer)
295 INETXPORT_COMPLETION_FUNCTION fnCompletion = This->fnCompletion;
296 char *pBuffer;
298 This->fnCompletion = NULL;
299 pBuffer = This->pBuffer;
300 This->pBuffer = NULL;
301 fnCompletion((IInternetTransport *)&This->u.vtbl, pBuffer,
302 This->iCurrentBufferOffset);
303 HeapFree(GetProcessHeap(), 0, pBuffer);
304 return 0;
307 if (WSAAsyncSelect(This->Socket, hwnd, uMsg, FD_READ) == SOCKET_ERROR)
309 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
310 /* FIXME: handle error */
312 return 0;
314 else if (uMsg == IX_READLINE)
316 InternetTransport *This = (InternetTransport *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
318 /* no work to do */
319 if (!This->fnCompletion)
320 return 0;
322 while (This->iCurrentBufferOffset < This->cbBuffer - 1)
324 struct timeval tv;
325 fd_set infd;
327 if (recv(This->Socket, &This->pBuffer[This->iCurrentBufferOffset], 1, 0) <= 0)
329 if (WSAGetLastError() == WSAEWOULDBLOCK)
330 break;
332 ERR("recv failed with error %d\n", WSAGetLastError());
333 /* FIXME: handle error */
334 return 0;
337 if (This->pBuffer[This->iCurrentBufferOffset] == '\n')
339 INETXPORT_COMPLETION_FUNCTION fnCompletion = This->fnCompletion;
340 char *pBuffer;
342 This->fnCompletion = NULL;
343 This->pBuffer[This->iCurrentBufferOffset++] = '\0';
344 pBuffer = This->pBuffer;
345 This->pBuffer = NULL;
347 fnCompletion((IInternetTransport *)&This->u.vtbl, pBuffer,
348 This->iCurrentBufferOffset);
350 HeapFree(GetProcessHeap(), 0, pBuffer);
351 return 0;
353 if (This->pBuffer[This->iCurrentBufferOffset] != '\r')
354 This->iCurrentBufferOffset++;
356 FD_ZERO(&infd);
357 FD_SET(This->Socket, &infd);
358 tv.tv_sec = 0;
359 tv.tv_usec = 0;
361 if (This->iCurrentBufferOffset == This->cbBuffer - 1)
362 return 0;
364 if (WSAAsyncSelect(This->Socket, hwnd, uMsg, FD_READ) == SOCKET_ERROR)
366 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
367 /* FIXME: handle error */
369 return 0;
371 else
372 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
375 BOOL InternetTransport_RegisterClass(HINSTANCE hInstance)
377 WNDCLASSW cls;
378 WSADATA wsadata;
380 if (WSAStartup(MAKEWORD(2, 2), &wsadata))
381 return FALSE;
383 memset(&cls, 0, sizeof(cls));
384 cls.hInstance = hInstance;
385 cls.lpfnWndProc = InternetTransport_WndProc;
386 cls.lpszClassName = wszClassName;
388 return RegisterClassW(&cls);
391 void InternetTransport_UnregisterClass(HINSTANCE hInstance)
393 UnregisterClassW(wszClassName, hInstance);
394 WSACleanup();