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
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
;
49 This
->fCommandLogging
= FALSE
;
50 This
->fnCompletion
= NULL
;
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
));
64 HRESULT
InternetTransport_InetServerFromAccount(InternetTransport
*This
,
65 IImnAccount
*pAccount
, LPINETSERVER pInetServer
)
67 FIXME("(%p, %p): stub\n", pAccount
, pInetServer
);
71 HRESULT
InternetTransport_Connect(InternetTransport
*This
,
72 LPINETSERVER pInetServer
, boolean fAuthenticate
, boolean fCommandLogging
)
75 struct addrinfo
*ai_cur
;
76 struct addrinfo hints
;
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);
88 return HRESULT_FROM_WIN32(GetLastError());
89 SetWindowLongPtrW(This
->hwnd
, GWLP_USERDATA
, (LONG_PTR
)This
);
92 hints
.ai_family
= PF_UNSPEC
;
93 hints
.ai_socktype
= SOCK_STREAM
;
94 hints
.ai_protocol
= IPPROTO_TCP
;
97 hints
.ai_canonname
= 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
);
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
))
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");
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
);
140 InternetTransport_ChangeStatus(This
, IXP_CONNECTED
);
142 /* FIXME: call WSAAsyncSelect */
145 TRACE("connected\n");
151 return IXP_E_CANT_FIND_HOST
;
154 HRESULT
InternetTransport_HandsOffCallback(InternetTransport
*This
)
156 if (!This
->pCallback
)
159 ITransportCallback_Release(This
->pCallback
);
160 This
->pCallback
= NULL
;
165 HRESULT
InternetTransport_DropConnection(InternetTransport
*This
)
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
);
179 InternetTransport_ChangeStatus(This
, IXP_DISCONNECTED
);
184 HRESULT
InternetTransport_GetStatus(InternetTransport
*This
,
185 IXPSTATUS
*pCurrentStatus
)
187 *pCurrentStatus
= This
->Status
;
191 HRESULT
InternetTransport_ChangeStatus(InternetTransport
*This
, IXPSTATUS Status
)
193 This
->Status
= Status
;
195 ITransportCallback_OnStatus(This
->pCallback
, Status
,
196 (IInternetTransport
*)&This
->u
.vtbl
);
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
)
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 */
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
)
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 */
246 HRESULT
InternetTransport_Write(InternetTransport
*This
, const char *pvData
,
247 int cbSize
, INETXPORT_COMPLETION_FUNCTION fnCompletion
)
251 if (This
->Status
== IXP_DISCONNECTED
)
252 return IXP_E_NOT_CONNECTED
;
254 if (This
->fnCompletion
)
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);
270 static LRESULT CALLBACK
InternetTransport_WndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
274 InternetTransport
*This
= (InternetTransport
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
277 if (!This
->fnCompletion
)
280 while (This
->iCurrentBufferOffset
< This
->cbBuffer
)
282 if (recv(This
->Socket
, &This
->pBuffer
[This
->iCurrentBufferOffset
], 1, 0) <= 0)
284 if (WSAGetLastError() == WSAEWOULDBLOCK
)
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
;
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
);
307 if (WSAAsyncSelect(This
->Socket
, hwnd
, uMsg
, FD_READ
) == SOCKET_ERROR
)
309 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
310 /* FIXME: handle error */
314 else if (uMsg
== IX_READLINE
)
316 InternetTransport
*This
= (InternetTransport
*)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
319 if (!This
->fnCompletion
)
322 while (This
->iCurrentBufferOffset
< This
->cbBuffer
- 1)
327 if (recv(This
->Socket
, &This
->pBuffer
[This
->iCurrentBufferOffset
], 1, 0) <= 0)
329 if (WSAGetLastError() == WSAEWOULDBLOCK
)
332 ERR("recv failed with error %d\n", WSAGetLastError());
333 /* FIXME: handle error */
337 if (This
->pBuffer
[This
->iCurrentBufferOffset
] == '\n')
339 INETXPORT_COMPLETION_FUNCTION fnCompletion
= This
->fnCompletion
;
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
);
353 if (This
->pBuffer
[This
->iCurrentBufferOffset
] != '\r')
354 This
->iCurrentBufferOffset
++;
357 FD_SET(This
->Socket
, &infd
);
361 if (This
->iCurrentBufferOffset
== This
->cbBuffer
- 1)
364 if (WSAAsyncSelect(This
->Socket
, hwnd
, uMsg
, FD_READ
) == SOCKET_ERROR
)
366 ERR("WSAAsyncSelect failed with error %d\n", WSAGetLastError());
367 /* FIXME: handle error */
372 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
375 BOOL
InternetTransport_RegisterClass(HINSTANCE hInstance
)
380 if (WSAStartup(MAKEWORD(2, 2), &wsadata
))
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
);