1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
18 #include "network-internal.h"
20 /* InternetSetStatusCallback is pretty much useless for sync sockets.
21 * XXX should we change to async sockets? IIRC they're nothing but trouble.
22 * for now, not worth the effort. */
23 #undef USE_INTERNET_STATUS_CALLBACK
26 net_getlasterror(GError
**err
) {
28 HMODULE hModule
= NULL
;
29 DWORD errcode
= GetLastError();
31 if (errcode
> INTERNET_ERROR_BASE
&& errcode
<= INTERNET_ERROR_LAST
)
32 hModule
= LoadLibraryEx("wininet.dll", NULL
,
33 LOAD_LIBRARY_AS_DATAFILE
);
36 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
37 FORMAT_MESSAGE_IGNORE_INSERTS
|
39 FORMAT_MESSAGE_FROM_HMODULE
:
40 FORMAT_MESSAGE_FROM_SYSTEM
),
43 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
47 g_set_error(err
, 0, 0, "Unable to lookup error code.");
49 g_set_error(err
, 0, 0, lpMsgBuf
);
54 #ifdef USE_INTERNET_STATUS_CALLBACK
56 net_internetstatus_cb(HINTERNET hInternet
, DWORD_PTR dwContext
,
57 DWORD dwInternetStatus
, LPVOID lpStatusInformation
,
58 DWORD dwStatusLength
) {
60 g_print("status %ld\n", dwInternetStatus
);
62 #endif /* USE_INTERNET_STATUS_CALLBACK */
65 readresponse(HINTERNET hRequest
,
66 NetStatusCallback cb
, gpointer data
,
68 char buf
[READ_BLOCK_SIZE
];
70 NetStatusProgress progress
= {0};
75 HttpQueryInfo(hRequest
,
76 HTTP_QUERY_CONTENT_LENGTH
| HTTP_QUERY_FLAG_NUMBER
,
77 &progress
.total
, &len
, NULL
);
79 if (cb
) cb(NET_STATUS_PROGRESS
, &progress
, data
);
81 response
= g_string_sized_new(READ_BLOCK_SIZE
);
82 len
= READ_BLOCK_SIZE
;
83 while (InternetReadFile(hRequest
, buf
, READ_BLOCK_SIZE
, &len
) &&
85 g_string_append_len(response
, buf
, len
);
86 progress
.current
+= len
;
87 if (cb
) cb(NET_STATUS_PROGRESS
, &progress
, data
);
88 len
= READ_BLOCK_SIZE
;
91 net_getlasterror(err
);
92 g_string_free(response
, TRUE
);
95 if (progress
.total
> 0 && progress
.current
< progress
.total
) {
96 g_set_error(err
, 0, 0, _("The connection was closed."));
97 g_string_free(response
, TRUE
);
105 net_post_blocking(const char *surl
, GSList
*headers
, GString
*post
,
106 NetStatusCallback cb
, gpointer data
,
108 HINTERNET hInternet
, hConnection
, hRequest
;
109 GString
*response
= NULL
;
111 URL_COMPONENTS urlc
= {0};
113 url
= g_strdup(surl
);
114 urlc
.dwStructSize
= sizeof(URL_COMPONENTS
);
115 urlc
.lpszHostName
= NULL
;
116 urlc
.dwHostNameLength
= (DWORD
)strlen(url
);
117 if (!InternetCrackUrl(url
, urlc
.dwHostNameLength
, 0, &urlc
)) {
118 net_getlasterror(err
);
122 /* host is a pointer to a place within url;
123 we modify this string directly, and just free
124 url when we're done. */
125 host
= urlc
.lpszHostName
;
126 host
[urlc
.dwHostNameLength
] = 0;
128 if ((hInternet
= InternetOpen("LogJam-Win32",
129 INTERNET_OPEN_TYPE_PRECONFIG
,
130 NULL
, NULL
, 0)) != NULL
) {
132 #ifdef USE_INTERNET_STATUS_CALLBACK
133 if (!InternetSetStatusCallback(hInternet
, net_internetstatus_cb
)) {
134 net_getlasterror(err
);
137 if ((hConnection
= InternetConnect(hInternet
,
140 INTERNET_SERVICE_HTTP
, 0, 0xDEADBEEF)) != NULL
) {
141 #else /* !USE_INTERNET_STATUS_CALLBACK */
142 if ((hConnection
= InternetConnect(hInternet
,
145 INTERNET_SERVICE_HTTP
, 0, 0)) != NULL
) {
146 #endif /* USE_INTERNET_STATUS_CALLBACK */
148 if ((hRequest
= HttpOpenRequest(hConnection
,
149 "POST", "/interface/flat",
150 NULL
, NULL
, NULL
, 0, 0)) != NULL
) {
152 if (HttpSendRequest(hRequest
, NULL
, 0,
153 post
->str
, post
->len
)) {
154 response
= readresponse(hRequest
, cb
, data
, err
);
156 net_getlasterror(err
);
158 InternetCloseHandle(hRequest
);
160 net_getlasterror(err
);
162 InternetCloseHandle(hConnection
);
164 net_getlasterror(err
);
166 InternetCloseHandle(hInternet
);
168 net_getlasterror(err
);
184 NetStatusCallback user_cb
;
188 void status_to_pipe_cb(NetStatusType status
,
189 gpointer statusdata
, gpointer data
) {
190 ThreadData
*threaddata
= (ThreadData
*)data
;
193 case NET_STATUS_PROGRESS
:
194 write(threaddata
->pipe
, &t
, 1);
195 write(threaddata
->pipe
, statusdata
, sizeof(NetStatusProgress
));
198 g_warning("status_to_pipe_cb: unknown status %d.\n", status
);
203 net_post_threadproc(LPVOID param
) {
204 ThreadData
*threaddata
= (ThreadData
*)param
;
205 char t
= NET_STATUS_DONE
;
206 threaddata
->response
=
207 net_post_blocking(threaddata
->url
,
208 threaddata
->headers
, threaddata
->post
,
209 status_to_pipe_cb
, threaddata
,
211 write(threaddata
->pipe
, &t
, 1);
216 net_post_input_cb(GIOChannel
*source
, GIOCondition condition
, gpointer data
) {
217 ThreadData
*threaddata
= (ThreadData
*)data
;
219 NetStatusProgress progress
;
222 g_io_channel_read_chars(source
, &t
, 1, NULL
, NULL
);
224 case NET_STATUS_PROGRESS
:
225 g_io_channel_read_chars(source
, (gchar
*)&progress
,
226 sizeof(NetStatusProgress
), NULL
, NULL
);
227 threaddata
->user_cb(NET_STATUS_PROGRESS
, &progress
,
228 threaddata
->user_data
);
230 case NET_STATUS_DONE
:
231 g_source_destroy(threaddata
->source
);
232 g_main_loop_quit(threaddata
->mainloop
);
235 g_warning("net_post_input_cb: unknown status %d.\n", t
);
238 if (t
== NET_STATUS_DONE
)
244 net_post_mainloop(const char *url
, GSList
*headers
, GString
*post
,
245 NetStatusCallback cb
, gpointer data
,
247 ThreadData threaddata
= {0};
254 if (_pipe(fds
, 4096, _O_BINARY
) < 0)
257 mainloop
= g_main_loop_new(NULL
, TRUE
);
259 // XXX http://mail.gnome.org/archives/gtk-devel-list/2003-June/msg00102.html
260 channel
= g_io_channel_unix_new(fds
[0]);
261 g_io_channel_set_encoding(channel
, NULL
, NULL
);
262 g_io_channel_set_buffered(channel
, FALSE
);
263 source
= g_io_create_watch(channel
, G_IO_IN
| G_IO_HUP
| G_IO_ERR
);
264 g_source_set_callback(source
,
265 (GSourceFunc
)net_post_input_cb
,
267 g_source_attach(source
, NULL
);
269 threaddata
.mainloop
= mainloop
;
270 threaddata
.source
= source
;
271 threaddata
.pipe
= fds
[1];
272 threaddata
.headers
= headers
;
273 threaddata
.post
= post
;
274 threaddata
.url
= url
;
275 threaddata
.err
= err
;
276 threaddata
.user_cb
= cb
;
277 threaddata
.user_data
= data
;
279 g_print("starting thread\n");
281 CreateThread(NULL
, 0, net_post_threadproc
, &threaddata
, 0, &threadid
);
283 g_main_loop_run(mainloop
);
285 /* XXX: closing these in the opposite order causes deadlocks? */
289 g_io_channel_unref(channel
);
290 /* source is destroyed in the callback. */
291 g_main_loop_unref(mainloop
);
293 return threaddata
.response
;
297 net_mainloop_cancel(NetMainloopHandle handle
) {
298 /* XXX implement me. */