Add utility program for fetching URL with installed client certificate 0.4
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu Nov 10 11:19:34 2011 +0000 (2011-11-10)
changeset 1429d8bb64056c
parent 13 b0a35bae4961
child 15 06caf639d95e
child 16 596d5cf9a807
Add utility program for fetching URL with installed client certificate
app-manager/Makefile.am
app-manager/fetch.c
     1.1 --- a/app-manager/Makefile.am	Thu Nov 10 11:15:09 2011 +0000
     1.2 +++ b/app-manager/Makefile.am	Thu Nov 10 11:19:34 2011 +0000
     1.3 @@ -1,9 +1,11 @@
     1.4  AM_CFLAGS=$(GUI_CFLAGS) -g -DPLOVER_DATADIR=\""$(pkgdatadir)"\" -I$(top_srcdir)
     1.5  LDADD=../plover/libplover.la ../plover-gtk/libplover-gtk.la $(GUI_LIBS)
     1.6  
     1.7 -bin_PROGRAMS=app-manager
     1.8 +bin_PROGRAMS=app-manager fetch
     1.9  app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \
    1.10  	localmedia.c localmedia.h
    1.11 +fetch_SOURCES=fetch.c
    1.12 +fetch_LDADD=$(LDADD) -lcrypt32
    1.13  if HAVE_WINDRES
    1.14  app_manager_SOURCES+=resources.rc app-manager.exe.manifest
    1.15  endif
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/app-manager/fetch.c	Thu Nov 10 11:19:34 2011 +0000
     2.3 @@ -0,0 +1,411 @@
     2.4 +/*
     2.5 + * A program to explore http support on MS-Windows.
     2.6 + */
     2.7 +
     2.8 +#include "config.h"
     2.9 +#include <stdlib.h>
    2.10 +#include <stdio.h>
    2.11 +#include <glib.h>
    2.12 +#include <razor.h>
    2.13 +#if HAVE_WINHTTP_H
    2.14 +#include <windows.h>
    2.15 +#include <winhttp.h>
    2.16 +#include <wincrypt.h>
    2.17 +
    2.18 +#ifndef PKCS12_NO_PERSIST_KEY
    2.19 +#define PKCS12_NO_PERSIST_KEY 0x00008000
    2.20 +#endif
    2.21 +
    2.22 +static gboolean debug=FALSE;
    2.23 +
    2.24 +static GOptionEntry entries[] = 
    2.25 +{
    2.26 +    { "debug",'d',0,G_OPTION_ARG_NONE,&debug,"Output debugging",NULL },
    2.27 +    { NULL }
    2.28 +};
    2.29 +
    2.30 +static struct WinHttpFuncs
    2.31 +{
    2.32 +    WINBOOL (WINAPI *AddRequestHeaders)(HINTERNET,LPCWSTR,DWORD,DWORD);
    2.33 +    WINBOOL (WINAPI *DetectAutoProxyConfigUrl)(DWORD,LPWSTR*);
    2.34 +    WINBOOL (WINAPI *CheckPlatform)(void);
    2.35 +    WINBOOL (WINAPI *CloseHandle)(HINTERNET);
    2.36 +    HINTERNET (WINAPI *Connect)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD);
    2.37 +    WINBOOL (WINAPI *CrackUrl)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS);
    2.38 +    WINBOOL (WINAPI *CreateUrl)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD);
    2.39 +    WINBOOL (WINAPI *GetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
    2.40 +    WINBOOL (WINAPI *GetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
    2.41 +    WINBOOL (WINAPI *GetProxyForUrl)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*);
    2.42 +    HINTERNET (WINAPI *Open)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD);
    2.43 +    HINTERNET (WINAPI *OpenRequest)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD);
    2.44 +    WINBOOL (WINAPI *QueryAuthParams)(HINTERNET,DWORD,LPVOID*);
    2.45 +    WINBOOL (WINAPI *QueryAuthSchemes)(HINTERNET,LPDWORD,LPDWORD,LPDWORD);
    2.46 +    WINBOOL (WINAPI *QueryDataAvailable)(HINTERNET,LPDWORD);
    2.47 +    WINBOOL (WINAPI *QueryHeaders)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD);
    2.48 +    WINBOOL (WINAPI *QueryOption)(HINTERNET,DWORD,LPVOID,LPDWORD);
    2.49 +    WINBOOL (WINAPI *ReadData)(HINTERNET,LPVOID,DWORD,LPDWORD);
    2.50 +    WINBOOL (WINAPI *ReceiveResponse)(HINTERNET,LPVOID);
    2.51 +    WINBOOL (WINAPI *SendRequest)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR);
    2.52 +    WINBOOL (WINAPI *SetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
    2.53 +    WINBOOL (WINAPI *SetCredentials)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID);
    2.54 +    WINBOOL (WINAPI *SetOption)(HINTERNET,DWORD,LPVOID,DWORD);
    2.55 +    WINHTTP_STATUS_CALLBACK (WINAPI *SetStatusCallback)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR);
    2.56 +    WINBOOL (WINAPI *SetTimeouts)(HINTERNET,int,int,int,int);
    2.57 +    WINBOOL (WINAPI *TimeFromSystemTime)(CONST SYSTEMTIME *,LPWSTR);
    2.58 +    WINBOOL (WINAPI *TimeToSystemTime)(LPCWSTR,SYSTEMTIME*);
    2.59 +    WINBOOL (WINAPI *WriteData)(HINTERNET,LPCVOID,DWORD,LPDWORD);
    2.60 +} WinHttp;
    2.61 +
    2.62 +static int plover_init_winhttp(void)
    2.63 +{
    2.64 +    HMODULE module;
    2.65 +    if (WinHttp.Open)
    2.66 +	return 0;
    2.67 +    module=LoadLibraryA("winhttp.dll");
    2.68 +    if (!module)
    2.69 +	return -1;
    2.70 +    WinHttp.AddRequestHeaders=
    2.71 +      (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,DWORD))
    2.72 +      GetProcAddress(module,"WinHttpAddRequestHeaders");
    2.73 +    WinHttp.DetectAutoProxyConfigUrl=
    2.74 +      (WINBOOL (WINAPI *)(DWORD,LPWSTR*))
    2.75 +      GetProcAddress(module,"WinHttpDetectAutoProxyConfigUrl");
    2.76 +    WinHttp.CheckPlatform=(WINBOOL (WINAPI *)(void))
    2.77 +      GetProcAddress(module,"WinHttpCheckPlatform");
    2.78 +    WinHttp.CloseHandle=(WINBOOL (WINAPI *)(HINTERNET))
    2.79 +      GetProcAddress(module,"WinHttpCloseHandle");
    2.80 +    WinHttp.Connect=
    2.81 +      (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD))
    2.82 +      GetProcAddress(module,"WinHttpConnect");
    2.83 +    WinHttp.CrackUrl=(WINBOOL (WINAPI *)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS))
    2.84 +      GetProcAddress(module,"WinHttpCrackUrl");
    2.85 +    WinHttp.CreateUrl=
    2.86 +      (WINBOOL (WINAPI *)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD))
    2.87 +      GetProcAddress(module,"WinHttpCreateUrl");
    2.88 +    WinHttp.GetDefaultProxyConfiguration=
    2.89 +      (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
    2.90 +      GetProcAddress(module,"WinHttpGetDefaultProxyConfiguration");
    2.91 +    WinHttp.GetIEProxyConfigForCurrentUser=
    2.92 +      (WINBOOL (WINAPI *)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*))
    2.93 +      GetProcAddress(module,"WinHttpGetIEProxyConfigForCurrentUser");
    2.94 +    WinHttp.GetProxyForUrl=
    2.95 +      (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*))
    2.96 +      GetProcAddress(module,"WinHttpGetProxyForUrl");
    2.97 +    WinHttp.Open=(HINTERNET (WINAPI *)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD))
    2.98 +      GetProcAddress(module,"WinHttpOpen");
    2.99 +    WinHttp.OpenRequest=
   2.100 +      (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD))
   2.101 +      GetProcAddress(module,"WinHttpOpenRequest");
   2.102 +    WinHttp.QueryAuthParams=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID*))
   2.103 +      GetProcAddress(module,"WinHttpQueryAuthParams");
   2.104 +    WinHttp.QueryAuthSchemes=
   2.105 +      (WINBOOL (WINAPI *)(HINTERNET,LPDWORD,LPDWORD,LPDWORD))
   2.106 +      GetProcAddress(module,"WinHttpQueryAuthSchemes");
   2.107 +    WinHttp.QueryDataAvailable=(WINBOOL (WINAPI *)(HINTERNET,LPDWORD))
   2.108 +      GetProcAddress(module,"WinHttpQueryDataAvailable");
   2.109 +    WinHttp.QueryHeaders=
   2.110 +      (WINBOOL (WINAPI *)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD))
   2.111 +      GetProcAddress(module,"WinHttpQueryHeaders");
   2.112 +    WinHttp.QueryOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,LPDWORD))
   2.113 +      GetProcAddress(module,"WinHttpQueryOption");
   2.114 +    WinHttp.ReadData=(WINBOOL (WINAPI *)(HINTERNET,LPVOID,DWORD,LPDWORD))
   2.115 +      GetProcAddress(module,"WinHttpReadData");
   2.116 +    WinHttp.ReceiveResponse=(WINBOOL (WINAPI *)(HINTERNET,LPVOID))
   2.117 +      GetProcAddress(module,"WinHttpReceiveResponse");
   2.118 +    WinHttp.SendRequest=
   2.119 +      (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR))
   2.120 +      GetProcAddress(module,"WinHttpSendRequest");
   2.121 +    WinHttp.SetDefaultProxyConfiguration=
   2.122 +      (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
   2.123 +      GetProcAddress(module,"WinHttpSetDefaultProxyConfiguration");
   2.124 +    WinHttp.SetCredentials=
   2.125 +      (WINBOOL (WINAPI *)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID))
   2.126 +      GetProcAddress(module,"WinHttpSetCredentials");
   2.127 +    WinHttp.SetOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,DWORD))
   2.128 +      GetProcAddress(module,"WinHttpSetOption");
   2.129 +    WinHttp.SetStatusCallback=
   2.130 +      (WINHTTP_STATUS_CALLBACK (WINAPI *)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR))
   2.131 +      GetProcAddress(module,"WinHttpSetStatusCallback");
   2.132 +    WinHttp.SetTimeouts=(WINBOOL (WINAPI *)(HINTERNET,int,int,int,int))
   2.133 +      GetProcAddress(module,"WinHttpSetTimeouts");
   2.134 +    WinHttp.TimeFromSystemTime=(WINBOOL (WINAPI *)(CONST SYSTEMTIME *,LPWSTR))
   2.135 +      GetProcAddress(module,"WinHttpTimeFromSystemTime");
   2.136 +    WinHttp.TimeToSystemTime=(WINBOOL (WINAPI *)(LPCWSTR,SYSTEMTIME*))
   2.137 +      GetProcAddress(module,"WinHttpTimeToSystemTime");
   2.138 +    WinHttp.WriteData=(WINBOOL (WINAPI *)(HINTERNET,LPCVOID,DWORD,LPDWORD))
   2.139 +      GetProcAddress(module,"WinHttpWriteData");
   2.140 +    if (!WinHttp.CrackUrl || !WinHttp.Open || !WinHttp.Connect ||
   2.141 +        !WinHttp.OpenRequest || !WinHttp.SendRequest ||
   2.142 +	!WinHttp.ReceiveResponse || !WinHttp.QueryDataAvailable ||
   2.143 +	!WinHttp.ReadData || !WinHttp.CloseHandle)
   2.144 +    {
   2.145 +	FreeLibrary(module);
   2.146 +	WinHttp.Open=NULL;
   2.147 +	return -1;
   2.148 +    }
   2.149 +    return 0;
   2.150 +}
   2.151 +
   2.152 +/*
   2.153 + * This will find ${PREFIX}/${file} if it exists, but it may also
   2.154 + * find ${PREFIX}/.../${file} if ${PREFIX}/${file} does not exist.
   2.155 + * This seems unlikely and won't do any harm should it occur.
   2.156 + */
   2.157 +
   2.158 +gchar *find_prefixed_file(const char *file)
   2.159 +{
   2.160 +    int i,len;
   2.161 +    const char *name;
   2.162 +    char *install_root;
   2.163 +    struct razor_set *set;
   2.164 +    struct razor_atomic *atomic;
   2.165 +    struct razor_package *package;
   2.166 +    struct razor_package_iterator *pi;
   2.167 +    struct razor_file_iterator *fi;
   2.168 +    gchar *retval=NULL;
   2.169 +    len=strlen(file);
   2.170 +    install_root=getenv("RAZOR_ROOT");
   2.171 +    if (!install_root)
   2.172 +	install_root="";
   2.173 +    atomic=razor_atomic_open("Query packages");
   2.174 +    set=razor_root_open_read_only(install_root,atomic);
   2.175 +    if (set)
   2.176 +    {
   2.177 +	pi=razor_package_iterator_create(set);
   2.178 +	while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
   2.179 +	{
   2.180 +	    fi=razor_file_iterator_create(set,package,0);
   2.181 +	    while (!retval && razor_file_iterator_next(fi,&name))
   2.182 +	    {
   2.183 +		i=strlen(name)-len;
   2.184 +		if (i>0 && name[i-1]=='/' && !strcmp(name+i,file))
   2.185 +		{
   2.186 +		    if (!retval || strlen(retval)>strlen(name))
   2.187 +		    {
   2.188 +			g_free(retval);
   2.189 +			retval=g_strdup(name);
   2.190 +		    }
   2.191 +		}
   2.192 +	    }
   2.193 +	    razor_file_iterator_destroy(fi);
   2.194 +	}
   2.195 +	razor_package_iterator_destroy(pi);
   2.196 +	razor_set_unref(set);
   2.197 +    }
   2.198 +    razor_atomic_destroy(atomic);
   2.199 +    return retval;
   2.200 +}
   2.201 +
   2.202 +static HCERTSTORE plover_p12_import(const char *file,const wchar_t *password)
   2.203 +{
   2.204 +    GError *error=NULL;
   2.205 +    gchar *p12,*path,*s;
   2.206 +    gsize len;
   2.207 +    CRYPT_DATA_BLOB pfx;
   2.208 +    HCERTSTORE store;
   2.209 +    s=g_build_path("/","etc","pki",file,NULL);
   2.210 +    path=find_prefixed_file(s);
   2.211 +    if (!path)
   2.212 +    {
   2.213 +	g_printerr("%s: Not installed\n",s);
   2.214 +	g_free(s);
   2.215 +	return NULL;
   2.216 +    }
   2.217 +    g_free(s);
   2.218 +    if (!g_file_get_contents(path,&p12,&len,&error))
   2.219 +    {
   2.220 +	g_printerr("%s: %s\n",path,error->message);
   2.221 +	g_free(path);
   2.222 +	g_error_free(error);
   2.223 +	return NULL;
   2.224 +    }
   2.225 +    g_free(path);
   2.226 +    pfx.pbData=(BYTE *)p12;
   2.227 +    pfx.cbData=len;
   2.228 +    store=PFXImportCertStore(&pfx,password,PKCS12_NO_PERSIST_KEY);
   2.229 +    if (!store)
   2.230 +	g_printerr("PFXImportCertStore failed. Err: %lu\n",GetLastError());
   2.231 +    g_free(p12);
   2.232 +    return store;
   2.233 +}
   2.234 +
   2.235 +static const CERT_CONTEXT *plover_get_client_certificate(HCERTSTORE store)
   2.236 +{
   2.237 +    const CERT_CONTEXT *iter,*cert;
   2.238 +    cert=NULL;
   2.239 +    iter=CertEnumCertificatesInStore(store,NULL);
   2.240 +    while(iter)
   2.241 +    {
   2.242 +	if (!cert)
   2.243 +	    cert=CertDuplicateCertificateContext(iter);
   2.244 +	iter=CertEnumCertificatesInStore(store,iter);
   2.245 +    }
   2.246 +    return cert;
   2.247 +}
   2.248 +
   2.249 +void CALLBACK plover_status_callback(HINTERNET handle,DWORD_PTR context,
   2.250 +  DWORD status,LPVOID status_information,DWORD status_information_length)
   2.251 +{
   2.252 +    g_printerr("CB status 0x%lX",status);
   2.253 +    if (status==WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
   2.254 +	g_printerr(", flag 0x%lX",*(DWORD *)status_information);
   2.255 +    g_printerr("\n");
   2.256 +}
   2.257 +
   2.258 +int fetch(HINTERNET session,HCERTSTORE store,const char *url)
   2.259 +{
   2.260 +    URL_COMPONENTS components={0};
   2.261 +    HINTERNET connection,request;
   2.262 +    DWORD len,nb,options;
   2.263 +    char *buffer;
   2.264 +    wchar_t *ws;
   2.265 +    glong ws_len;
   2.266 +    gchar *hostname,*path;
   2.267 +    const CERT_CONTEXT *client_cert;
   2.268 +    components.dwStructSize=sizeof(components);
   2.269 +    components.dwSchemeLength=(DWORD)-1;
   2.270 +    components.dwHostNameLength=(DWORD)-1;
   2.271 +    components.dwUserNameLength=(DWORD)-1;
   2.272 +    components.dwPasswordLength=(DWORD)-1;
   2.273 +    components.dwUrlPathLength=(DWORD)-1;
   2.274 +    ws=g_utf8_to_utf16(url,-1,NULL,&ws_len,NULL);
   2.275 +    if (!ws || !WinHttp.CrackUrl(ws,ws_len,0,&components))
   2.276 +    {
   2.277 +	g_printerr("%s: Invalid or unsupported URL\n",url);
   2.278 +	return -1;
   2.279 +    }
   2.280 +    /* ICU_REJECT_USERPWD is not supported under Windows XP */
   2.281 +    if (components.dwUserNameLength || components.dwPasswordLength)
   2.282 +    {
   2.283 +	g_printerr("%s: Credentials not supported\n",url);
   2.284 +	return -1;
   2.285 +    }
   2.286 +    hostname=g_utf16_to_utf8(components.lpszHostName,
   2.287 +      components.dwHostNameLength,NULL,NULL,NULL);
   2.288 +    path=g_utf16_to_utf8(components.lpszUrlPath,components.dwUrlPathLength,NULL,
   2.289 +      NULL,NULL);
   2.290 +    g_free(ws);
   2.291 +    ws=g_utf8_to_utf16(hostname,-1,NULL,NULL,NULL);
   2.292 +    connection=WinHttp.Connect(session,ws,
   2.293 +      components.nPort?components.nPort:INTERNET_DEFAULT_PORT,0);
   2.294 +    g_free(ws);
   2.295 +    if (connection)
   2.296 +    {
   2.297 +	ws=g_utf8_to_utf16(path,-1,NULL,NULL,NULL);
   2.298 +	request=WinHttp.OpenRequest(connection,L"GET",ws,NULL,
   2.299 +	  WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,
   2.300 +	  components.nScheme==INTERNET_SCHEME_HTTPS?WINHTTP_FLAG_SECURE:0);
   2.301 +	g_free(ws);
   2.302 +	if (request)
   2.303 +	{
   2.304 +	    if (debug)
   2.305 +		(void)WinHttp.SetStatusCallback(request,plover_status_callback,
   2.306 +		  WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0);
   2.307 +	    if (components.nScheme==INTERNET_SCHEME_HTTPS && WinHttp.SetOption)
   2.308 +	    {
   2.309 +		options=SECURITY_FLAG_IGNORE_UNKNOWN_CA;
   2.310 +		(void)WinHttp.SetOption(request,WINHTTP_OPTION_SECURITY_FLAGS,
   2.311 +		  &options,sizeof(options));
   2.312 +		client_cert=plover_get_client_certificate(store);
   2.313 +		if (client_cert)
   2.314 +		{
   2.315 +		    if (!WinHttp.SetOption(request,
   2.316 +		      WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(void *)client_cert,
   2.317 +		      sizeof(*client_cert)))
   2.318 +			g_printerr("Failed to set client certificate (%lu)\n",
   2.319 +			  GetLastError());
   2.320 +		}
   2.321 +		else
   2.322 +		    g_printerr("No client certificate found\n");
   2.323 +	    }
   2.324 +	    if (!WinHttp.SendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS,
   2.325 +	      0,WINHTTP_NO_REQUEST_DATA,0,0,0))
   2.326 +		g_printerr("Failed to send request (%lu)\n",GetLastError());
   2.327 +	    else if (!WinHttp.ReceiveResponse(request,NULL))
   2.328 +		g_printerr("Failed to receive response (%lu)\n",GetLastError());
   2.329 +	    else
   2.330 +	    {
   2.331 +		do
   2.332 +		{
   2.333 +		    len=0;
   2.334 +		    if (!WinHttp.QueryDataAvailable(request,&len))
   2.335 +			g_printerr(
   2.336 +			  "Error %lu in WinHttpQueryDataAvailable.\n",
   2.337 +			  (unsigned long)GetLastError());
   2.338 +		    buffer=calloc(len+1,1);
   2.339 +		    if (!buffer)
   2.340 +			break;
   2.341 +		    else
   2.342 +		    {
   2.343 +			if (!WinHttp.ReadData(request,(void *)buffer,len,&nb))
   2.344 +			    g_printerr("Error %lu in WinHttpReadData.\n",
   2.345 +			      (unsigned long)GetLastError());
   2.346 +			else
   2.347 +			    printf("%s\n",buffer);
   2.348 +			free(buffer);
   2.349 +		    }
   2.350 +		} while (len>0);
   2.351 +	    }
   2.352 +	    WinHttp.CloseHandle(request);
   2.353 +	}
   2.354 +	else
   2.355 +	    g_printerr("Failed to open request for %s (%lu)\n",path,
   2.356 +	      GetLastError());
   2.357 +	WinHttp.CloseHandle(connection);
   2.358 +    }
   2.359 +    else
   2.360 +	g_printerr("Failed to open connection to %s\n",hostname);
   2.361 +    g_free(hostname);
   2.362 +    g_free(path);
   2.363 +    return 0;
   2.364 +}
   2.365 +
   2.366 +int main(int argc,char **argv)
   2.367 +{
   2.368 +    GError *error=NULL;
   2.369 +    GOptionContext *context;
   2.370 +    HCERTSTORE store;
   2.371 +    HINTERNET session;
   2.372 +    wchar_t *ws;
   2.373 +    context=g_option_context_new("URL - fetch a URL");
   2.374 +    g_option_context_add_main_entries(context,entries,NULL);
   2.375 +    if (!g_option_context_parse(context,&argc,&argv,&error))
   2.376 +    {
   2.377 +	g_printerr("Option parsing failed: %s\n",error->message);
   2.378 +	exit(1);
   2.379 +    }
   2.380 +    if (argc!=2)
   2.381 +    {
   2.382 +	g_printerr("%s\n",g_option_context_get_help(context,TRUE,NULL));
   2.383 +	exit(1);
   2.384 +    }
   2.385 +    if (plover_init_winhttp())
   2.386 +    {
   2.387 +	g_printerr("HTTP is not supported on this machine\n");
   2.388 +	exit(1);
   2.389 +    }
   2.390 +    store=plover_p12_import("system.p12",L"xyzzy-ylem");
   2.391 +    if (!store)
   2.392 +	exit(1);
   2.393 +    ws=g_utf8_to_utf16(PACKAGE_NAME "/" PACKAGE_VERSION,-1,NULL,NULL,NULL);
   2.394 +    session=WinHttp.Open(ws,WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
   2.395 +      WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0);
   2.396 +    free(ws);
   2.397 +    if (!session)
   2.398 +    {
   2.399 +	g_printerr("Failed to open WinHttp session\n");
   2.400 +	exit(1);
   2.401 +    }
   2.402 +    if (fetch(session,store,argv[1]))
   2.403 +	exit(1);
   2.404 +    WinHttp.CloseHandle(session);
   2.405 +    CertCloseStore(store,CERT_CLOSE_STORE_FORCE_FLAG);
   2.406 +    exit(0);
   2.407 +}
   2.408 +#else	/* !HAVE_WINHTTP_H */
   2.409 +main()
   2.410 +{
   2.411 +    g_printerr("HTTP is not supported on this machine\n");
   2.412 +    exit(1);
   2.413 +}
   2.414 +#endif	/* HAVE_WINHTTP_H */