user32: Dont create 16 bits heap in 64-bits mode
[wine/wine64.git] / dlls / inetcomm / internettransport.c
blob7cef414434a22460e41cf2c8209baad74eb80ab4
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 "winuser.h"
30 #include "winsock2.h"
31 #include "ws2tcpip.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "mimeole.h"
36 #include "wine/debug.h"
38 #include "inetcomm_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
42 static const WCHAR wszClassName[] = {'T','h','o','r','C','o','n','n','W','n','d','C','l','a','s','s',0};
44 #define IX_READ (WM_USER + 0)
45 #define IX_READLINE (WM_USER + 1)
46 #define IX_WRITE (WM_USER + 2)
48 HRESULT InternetTransport_Init(InternetTransport *This)
50 This->pCallback = NULL;
51 This->Status = IXP_DISCONNECTED;
52 This->Socket = -1;
53 This->fCommandLogging = FALSE;
54 This->fnCompletion = NULL;
56 return S_OK;
59 HRESULT InternetTransport_GetServerInfo(InternetTransport *This, LPINETSERVER pInetServer)
61 if (This->Status == IXP_DISCONNECTED)
62 return IXP_E_NOT_CONNECTED;
64 *pInetServer = This->ServerInfo;
65 return S_OK;
68 HRESULT InternetTransport_InetServerFromAccount(InternetTransport *This,
69 IImnAccount *pAccount, LPINETSERVER pInetServer)
71 FIXME("(%p, %p): stub\n", pAccount, pInetServer);
72 return E_NOTIMPL;
75 HRESULT InternetTransport_Connect(InternetTransport *This,
76 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
78 struct addrinfo *ai;
79 struct addrinfo *ai_cur;
80 struct addrinfo hints;
81 int ret;
82 char szPort[10];
84 if (This->Status != IXP_DISCONNECTED)
85 return IXP_E_ALREADY_CONNECTED;
87 This->ServerInfo = *pInetServer;
88 This->fCommandLogging = fCommandLogging;
90 This->hwnd = CreateWindowW(wszClassName, wszClassName, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0);
91 if (!This->hwnd)
92 return HRESULT_FROM_WIN32(GetLastError());
93 SetWindowLongPtrW(This->hwnd, GWLP_USERDATA, (LONG_PTR)This);
95 hints.ai_flags = 0;
96 hints.ai_family = PF_UNSPEC;
97 hints.ai_socktype = SOCK_STREAM;
98 hints.ai_protocol = IPPROTO_TCP;
99 hints.ai_addrlen = 0;
100 hints.ai_addr = NULL;
101 hints.ai_canonname = NULL;
102 hints.ai_next = NULL;
104 snprintf(szPort, sizeof(szPort), "%d", (unsigned short)pInetServer->dwPort);
106 InternetTransport_ChangeStatus(This, IXP_FINDINGHOST);
108 ret = getaddrinfo(pInetServer->szServerName, szPort, &hints, &ai);
109 if (ret)
111 ERR("getaddrinfo failed: %d\n", ret);
112 return IXP_E_CANT_FIND_HOST;
115 for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
117 int so;
119 if (TRACE_ON(inetcomm))
121 char host[256];
122 char service[256];
123 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
124 host, sizeof(host), service, sizeof(service),
125 NI_NUMERICHOST | NI_NUMERICSERV);
126 TRACE("trying %s:%s\n", host, service);
129 InternetTransport_ChangeStatus(This, IXP_CONNECTING);
131 so = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
132 if (so == -1)
134 WARN("socket() failed\n");
135 continue;
137 This->Socket = so;
139 /* FIXME: set to async */
141 if (0 > connect(This->Socket, ai_cur->ai_addr, ai_cur->ai_addrlen))
143 WARN("connect() failed\n");
144 closesocket(This->Socket);
145 continue;
147 InternetTransport_ChangeStatus(This, IXP_CONNECTED);
149 /* FIXME: call WSAAsyncSelect */
151 freeaddrinfo(ai);
152 TRACE("connected\n");
153 return S_OK;
156 freeaddrinfo(ai);
158 return IXP_E_CANT_FIND_HOST;
161 HRESULT InternetTransport_HandsOffCallback(InternetTransport *This)
163 if (!This->pCallback)
164 return S_FALSE;
166 ITransportCallback_Release(This->pCallback);
167 This->pCallback = NULL;
169 return S_OK;
172 HRESULT InternetTransport_DropConnection(InternetTransport *This)
174 int ret;
176 if (This->Status == IXP_DISCONNECTED)
177 return IXP_E_NOT_CONNECTED;
179 ret = shutdown(This->Socket, SD_BOTH);
181 ret = closesocket(This->Socket);
183 DestroyWindow(This->hwnd);
184 This->hwnd = NULL;
186 InternetTransport_ChangeStatus(This, IXP_DISCONNECTED);
188 return S_OK;
191 HRESULT InternetTransport_GetStatus(InternetTransport *This,
192 IXPSTATUS *pCurrentStatus)
194 *pCurrentStatus = This->Status;
195 return S_OK;
198 HRESULT InternetTransport_ChangeStatus(InternetTransport *This, IXPSTATUS Status)
200 This->Status = Status;
201 if (This->pCallback)
202 ITransportCallback_OnStatus(This->pCallback, Status,
203 (IInternetTransport *)&This->u.vtbl);
204 return S_OK;
207 HRESULT InternetTransport_Read(InternetTransport *This, int cbBuffer,
208 INETXPORT_COMPLETION_FUNCTION fnCompletion)
210 if (This->Status == IXP_DISCONNECTED)
211 return IXP_E_NOT_CONNECTED;
213 if (This->fnCompletion)
214 return IXP_E_BUSY;
216 This->fnCompletion = fnCompletion;
218 This->cbBuffer = cbBuffer;
219 This->pBuffer = HeapAlloc(GetProcessHeap(), 0, This->cbBuffer);
220 This->iCurrentBufferOffset = 0;
222 if (WSAAsyncSelect(This->Socket, This->hwnd, IX_READ, FD_READ) == SOCKET_ERROR)
224 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
225 /* FIXME: handle error */
227 return S_OK;
230 HRESULT InternetTransport_ReadLine(InternetTransport *This,
231 INETXPORT_COMPLETION_FUNCTION fnCompletion)
233 if (This->Status == IXP_DISCONNECTED)
234 return IXP_E_NOT_CONNECTED;
236 if (This->fnCompletion)
237 return IXP_E_BUSY;
239 This->fnCompletion = fnCompletion;
241 This->cbBuffer = 1024;
242 This->pBuffer = HeapAlloc(GetProcessHeap(), 0, This->cbBuffer);
243 This->iCurrentBufferOffset = 0;
245 if (WSAAsyncSelect(This->Socket, This->hwnd, IX_READLINE, FD_READ) == SOCKET_ERROR)
247 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
248 /* FIXME: handle error */
250 return S_OK;
253 HRESULT InternetTransport_Write(InternetTransport *This, const char *pvData,
254 int cbSize, INETXPORT_COMPLETION_FUNCTION fnCompletion)
256 int ret;
258 if (This->Status == IXP_DISCONNECTED)
259 return IXP_E_NOT_CONNECTED;
261 if (This->fnCompletion)
262 return IXP_E_BUSY;
264 /* FIXME: do this asynchronously */
265 ret = send(This->Socket, pvData, cbSize, 0);
266 if (ret == SOCKET_ERROR)
268 ERR("send failed with error %d\n", WSAGetLastError());
269 /* FIXME: handle error */
272 fnCompletion((IInternetTransport *)&This->u.vtbl, NULL, 0);
274 return S_OK;
277 HRESULT InternetTransport_DoCommand(InternetTransport *This,
278 LPCSTR pszCommand, INETXPORT_COMPLETION_FUNCTION fnCompletion)
280 if (This->Status == IXP_DISCONNECTED)
281 return IXP_E_NOT_CONNECTED;
283 if (This->fnCompletion)
284 return IXP_E_BUSY;
286 if (This->pCallback && This->fCommandLogging)
288 ITransportCallback_OnCommand(This->pCallback, CMD_SEND, (LPSTR)pszCommand, 0,
289 (IInternetTransport *)&This->u.vtbl);
291 return InternetTransport_Write(This, pszCommand, strlen(pszCommand), fnCompletion);
294 static LRESULT CALLBACK InternetTransport_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
296 if (uMsg == IX_READ)
298 InternetTransport *This = (InternetTransport *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
300 /* no work to do */
301 if (!This->fnCompletion)
302 return 0;
304 while (This->iCurrentBufferOffset < This->cbBuffer)
306 if (recv(This->Socket, &This->pBuffer[This->iCurrentBufferOffset], 1, 0) <= 0)
308 if (WSAGetLastError() == WSAEWOULDBLOCK)
309 break;
311 ERR("recv failed with error %d\n", WSAGetLastError());
312 /* FIXME: handle error */
315 This->iCurrentBufferOffset++;
317 if (This->iCurrentBufferOffset == This->cbBuffer)
319 INETXPORT_COMPLETION_FUNCTION fnCompletion = This->fnCompletion;
320 char *pBuffer;
322 This->fnCompletion = NULL;
323 pBuffer = This->pBuffer;
324 This->pBuffer = NULL;
325 fnCompletion((IInternetTransport *)&This->u.vtbl, pBuffer,
326 This->iCurrentBufferOffset);
327 HeapFree(GetProcessHeap(), 0, pBuffer);
328 return 0;
331 if (WSAAsyncSelect(This->Socket, hwnd, uMsg, FD_READ) == SOCKET_ERROR)
333 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
334 /* FIXME: handle error */
336 return 0;
338 else if (uMsg == IX_READLINE)
340 InternetTransport *This = (InternetTransport *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
342 /* no work to do */
343 if (!This->fnCompletion)
344 return 0;
346 while (This->iCurrentBufferOffset < This->cbBuffer - 1)
348 fd_set infd;
350 if (recv(This->Socket, &This->pBuffer[This->iCurrentBufferOffset], 1, 0) <= 0)
352 if (WSAGetLastError() == WSAEWOULDBLOCK)
353 break;
355 ERR("recv failed with error %d\n", WSAGetLastError());
356 /* FIXME: handle error */
357 return 0;
360 if (This->pBuffer[This->iCurrentBufferOffset] == '\n')
362 INETXPORT_COMPLETION_FUNCTION fnCompletion = This->fnCompletion;
363 char *pBuffer;
365 This->fnCompletion = NULL;
366 This->pBuffer[This->iCurrentBufferOffset++] = '\0';
367 pBuffer = This->pBuffer;
368 This->pBuffer = NULL;
370 fnCompletion((IInternetTransport *)&This->u.vtbl, pBuffer,
371 This->iCurrentBufferOffset);
373 HeapFree(GetProcessHeap(), 0, pBuffer);
374 return 0;
376 if (This->pBuffer[This->iCurrentBufferOffset] != '\r')
377 This->iCurrentBufferOffset++;
379 FD_ZERO(&infd);
380 FD_SET(This->Socket, &infd);
382 if (This->iCurrentBufferOffset == This->cbBuffer - 1)
383 return 0;
385 if (WSAAsyncSelect(This->Socket, hwnd, uMsg, FD_READ) == SOCKET_ERROR)
387 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
388 /* FIXME: handle error */
390 return 0;
392 else
393 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
396 BOOL InternetTransport_RegisterClass(HINSTANCE hInstance)
398 WNDCLASSW cls;
399 WSADATA wsadata;
401 if (WSAStartup(MAKEWORD(2, 2), &wsadata))
402 return FALSE;
404 memset(&cls, 0, sizeof(cls));
405 cls.hInstance = hInstance;
406 cls.lpfnWndProc = InternetTransport_WndProc;
407 cls.lpszClassName = wszClassName;
409 return RegisterClassW(&cls);
412 void InternetTransport_UnregisterClass(HINSTANCE hInstance)
414 UnregisterClassW(wszClassName, hInstance);
415 WSACleanup();