Blame client/Android/android_freerdp.c

Packit 1fb8d4
/*
Packit 1fb8d4
   Android JNI Client Layer
Packit 1fb8d4
Packit 1fb8d4
   Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
   Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
Packit 1fb8d4
   Copyright 2013 Thincast Technologies GmbH, Author: Armin Novak
Packit 1fb8d4
   Copyright 2015 Bernhard Miklautz <bernhard.miklautz@thincast.com>
Packit 1fb8d4
   Copyright 2016 Thincast Technologies GmbH
Packit 1fb8d4
   Copyright 2016 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
Packit 1fb8d4
   This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
Packit Service 5a9772
   If a copy of the MPL was not distributed with this file, You can obtain one at
Packit Service 5a9772
   http://mozilla.org/MPL/2.0/.
Packit 1fb8d4
*/
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <assert.h>
Packit 1fb8d4
#include <locale.h>
Packit 1fb8d4
Packit 1fb8d4
#include <jni.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/graphics.h>
Packit 1fb8d4
#include <freerdp/codec/rfx.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
#include <freerdp/gdi/gfx.h>
Packit 1fb8d4
#include <freerdp/client/rdpei.h>
Packit 1fb8d4
#include <freerdp/client/rdpgfx.h>
Packit 1fb8d4
#include <freerdp/client/cliprdr.h>
Packit 1fb8d4
#include <freerdp/channels/channels.h>
Packit 1fb8d4
#include <freerdp/client/channels.h>
Packit 1fb8d4
#include <freerdp/client/cmdline.h>
Packit 1fb8d4
#include <freerdp/constants.h>
Packit 1fb8d4
#include <freerdp/locale/keyboard.h>
Packit 1fb8d4
#include <freerdp/primitives.h>
Packit 1fb8d4
#include <freerdp/version.h>
Packit 1fb8d4
#include <freerdp/settings.h>
Packit 1fb8d4
#include <freerdp/utils/signal.h>
Packit 1fb8d4
Packit 1fb8d4
#include <android/bitmap.h>
Packit 1fb8d4
Packit 1fb8d4
#include "android_jni_callback.h"
Packit 1fb8d4
#include "android_jni_utils.h"
Packit 1fb8d4
#include "android_cliprdr.h"
Packit 1fb8d4
#include "android_freerdp_jni.h"
Packit 1fb8d4
Packit 1fb8d4
#if defined(WITH_GPROF)
Packit 1fb8d4
#include "jni/prof.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("android")
Packit 1fb8d4
Packit 1fb8d4
/* Defines the JNI version supported by this library. */
Packit Service 5a9772
#define FREERDP_JNI_VERSION "2.1.1"
Packit 1fb8d4
Packit Service 5a9772
static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	androidContext* afc;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !e)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", __FUNCTION__, context, (void*)e);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	afc = (androidContext*)context;
Packit 1fb8d4
	settings = afc->rdpCtx.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (settings->SoftwareGdi)
Packit 1fb8d4
		{
Packit Service 5a9772
			gdi_graphics_pipeline_init(afc->rdpCtx.gdi, (RdpgfxClientContext*)e->pInterface);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_WARN(TAG, "GFX without software GDI requested. "
Packit Service 5a9772
			               " This is not supported, add /gdi:sw");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		android_cliprdr_init(afc, (CliprdrClientContext*)e->pInterface);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void android_OnChannelDisconnectedEventHandler(void* context,
Packit Service 5a9772
                                                      ChannelDisconnectedEventArgs* e)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	androidContext* afc;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !e)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", __FUNCTION__, context, (void*)e);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	afc = (androidContext*)context;
Packit 1fb8d4
	settings = afc->rdpCtx.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (settings->SoftwareGdi)
Packit 1fb8d4
		{
Packit Service 5a9772
			gdi_graphics_pipeline_uninit(afc->rdpCtx.gdi, (RdpgfxClientContext*)e->pInterface);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_WARN(TAG, "GFX without software GDI requested. "
Packit Service 5a9772
			               " This is not supported, add /gdi:sw");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		android_cliprdr_uninit(afc, (CliprdrClientContext*)e->pInterface);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_begin_paint(rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_end_paint(rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	HGDI_WND hwnd;
Packit 1fb8d4
	int ninvalid;
Packit 1fb8d4
	rdpGdi* gdi;
Packit 1fb8d4
	HGDI_RGN cinvalid;
Packit 1fb8d4
	int x1, y1, x2, y2;
Packit 1fb8d4
	androidContext* ctx = (androidContext*)context;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!ctx || !context->instance)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = context->instance->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	gdi = context->gdi;
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi || !gdi->primary || !gdi->primary->hdc)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	hwnd = ctx->rdpCtx.gdi->primary->hdc->hwnd;
Packit 1fb8d4
Packit 1fb8d4
	if (!hwnd)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	ninvalid = hwnd->ninvalid;
Packit 1fb8d4
Packit Service 5a9772
	if (ninvalid < 1)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	cinvalid = hwnd->cinvalid;
Packit 1fb8d4
Packit 1fb8d4
	if (!cinvalid)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	x1 = cinvalid[0].x;
Packit 1fb8d4
	y1 = cinvalid[0].y;
Packit 1fb8d4
	x2 = cinvalid[0].x + cinvalid[0].w;
Packit 1fb8d4
	y2 = cinvalid[0].y + cinvalid[0].h;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < ninvalid; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		x1 = MIN(x1, cinvalid[i].x);
Packit 1fb8d4
		y1 = MIN(y1, cinvalid[i].y);
Packit 1fb8d4
		x2 = MAX(x2, cinvalid[i].x + cinvalid[i].w);
Packit 1fb8d4
		y2 = MAX(y2, cinvalid[i].y + cinvalid[i].h);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	freerdp_callback("OnGraphicsUpdate", "(JIIII)V", (jlong)context->instance, x1, y1, x2 - x1,
Packit Service 5a9772
	                 y2 - y1);
Packit Service 5a9772
Packit Service 5a9772
	hwnd->invalid->null = TRUE;
Packit Service 5a9772
	hwnd->ninvalid = 0;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_desktop_resize(rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context || !context->instance || !context->settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	freerdp_callback("OnGraphicsResize", "(JIII)V", (jlong)context->instance,
Packit Service 5a9772
	                 context->settings->DesktopWidth, context->settings->DesktopHeight,
Packit Service 5a9772
	                 context->settings->ColorDepth);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_pre_connect(freerdp* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	int rc;
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!instance)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = instance->settings;
Packit 1fb8d4
Packit Service 5a9772
	if (!settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	rc = PubSub_SubscribeChannelConnected(instance->context->pubSub,
Packit Service 5a9772
	                                      android_OnChannelConnectedEventHandler);
Packit 1fb8d4
Packit 1fb8d4
	if (rc != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not subscribe to connect event handler [%l08X]", rc);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	rc = PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
Packit Service 5a9772
	                                         android_OnChannelDisconnectedEventHandler);
Packit 1fb8d4
Packit 1fb8d4
	if (rc != CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not subscribe to disconnect event handler [%l08X]", rc);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!freerdp_client_load_addins(instance->context->channels, instance->settings))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to load addins [%l08X]", GetLastError());
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	freerdp_callback("OnPreConnect", "(J)V", (jlong)instance);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_Pointer_New(rdpContext* context, rdpPointer* pointer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context || !pointer || !context->gdi)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void android_Pointer_Free(rdpContext* context, rdpPointer* pointer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context || !pointer)
Packit 1fb8d4
		return;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL android_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL android_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_Pointer_SetNull(rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_Pointer_SetDefault(rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_register_pointer(rdpGraphics* graphics)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPointer pointer;
Packit 1fb8d4
Packit 1fb8d4
	if (!graphics)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pointer.size = sizeof(pointer);
Packit 1fb8d4
	pointer.New = android_Pointer_New;
Packit 1fb8d4
	pointer.Free = android_Pointer_Free;
Packit 1fb8d4
	pointer.Set = android_Pointer_Set;
Packit 1fb8d4
	pointer.SetNull = android_Pointer_SetNull;
Packit 1fb8d4
	pointer.SetDefault = android_Pointer_SetDefault;
Packit 1fb8d4
	pointer.SetPosition = android_Pointer_SetPosition;
Packit 1fb8d4
	graphics_register_pointer(graphics, &pointer);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_post_connect(freerdp* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	rdpUpdate* update;
Packit 1fb8d4
Packit 1fb8d4
	if (!instance || !instance->settings || !instance->context || !instance->update)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	update = instance->update;
Packit 1fb8d4
	settings = instance->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!gdi_init(instance, PIXEL_FORMAT_RGBA32))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_register_pointer(instance->context->graphics))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	instance->update->BeginPaint = android_begin_paint;
Packit 1fb8d4
	instance->update->EndPaint = android_end_paint;
Packit 1fb8d4
	instance->update->DesktopResize = android_desktop_resize;
Packit Service 5a9772
	freerdp_callback("OnSettingsChanged", "(JIII)V", (jlong)instance, settings->DesktopWidth,
Packit Service 5a9772
	                 settings->DesktopHeight, settings->ColorDepth);
Packit 1fb8d4
	freerdp_callback("OnConnectionSuccess", "(J)V", (jlong)instance);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void android_post_disconnect(freerdp* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp_callback("OnDisconnecting", "(J)V", (jlong)instance);
Packit 1fb8d4
	gdi_free(instance);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL android_authenticate_int(freerdp* instance, char** username, char** password,
Packit Service 5a9772
                                     char** domain, const char* cb_name)
Packit 1fb8d4
{
Packit 1fb8d4
	JNIEnv* env;
Packit 1fb8d4
	jboolean attached = jni_attach_thread(&env;;
Packit 1fb8d4
	jobject jstr1 = create_string_builder(env, *username);
Packit 1fb8d4
	jobject jstr2 = create_string_builder(env, *domain);
Packit 1fb8d4
	jobject jstr3 = create_string_builder(env, *password);
Packit 1fb8d4
	jboolean res;
Packit Service 5a9772
	res = freerdp_callback_bool_result(cb_name,
Packit Service 5a9772
	                                   "(JLjava/lang/StringBuilder;"
Packit Service 5a9772
	                                   "Ljava/lang/StringBuilder;"
Packit Service 5a9772
	                                   "Ljava/lang/StringBuilder;)Z",
Packit Service 5a9772
	                                   (jlong)instance, jstr1, jstr2, jstr3);
Packit 1fb8d4
Packit 1fb8d4
	if (res == JNI_TRUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		// read back string values
Packit 1fb8d4
		free(*username);
Packit 1fb8d4
		*username = get_string_from_string_builder(env, jstr1);
Packit 1fb8d4
		free(*domain);
Packit 1fb8d4
		*domain = get_string_from_string_builder(env, jstr2);
Packit 1fb8d4
		free(*password);
Packit 1fb8d4
		*password = get_string_from_string_builder(env, jstr3);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (attached == JNI_TRUE)
Packit 1fb8d4
		jni_detach_thread();
Packit 1fb8d4
Packit 1fb8d4
	return ((res == JNI_TRUE) ? TRUE : FALSE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL android_authenticate(freerdp* instance, char** username, char** password, char** domain)
Packit 1fb8d4
{
Packit Service 5a9772
	return android_authenticate_int(instance, username, password, domain, "OnAuthenticate");
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL android_gw_authenticate(freerdp* instance, char** username, char** password,
Packit Service 5a9772
                                    char** domain)
Packit 1fb8d4
{
Packit Service 5a9772
	return android_authenticate_int(instance, username, password, domain, "OnGatewayAuthenticate");
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static DWORD android_verify_certificate(freerdp* instance, const char* common_name,
Packit Service 5a9772
                                        const char* subject, const char* issuer,
Packit Service 5a9772
                                        const char* fingerprint, BOOL host_mismatch)
Packit 1fb8d4
{
Packit 1fb8d4
	WLog_DBG(TAG, "Certificate details:");
Packit 1fb8d4
	WLog_DBG(TAG, "\tSubject: %s", subject);
Packit 1fb8d4
	WLog_DBG(TAG, "\tIssuer: %s", issuer);
Packit 1fb8d4
	WLog_DBG(TAG, "\tThumbprint: %s", fingerprint);
Packit 1fb8d4
	WLog_DBG(TAG,
Packit 1fb8d4
	         "The above X.509 certificate could not be verified, possibly because you do not have "
Packit 1fb8d4
	         "the CA certificate in your certificate store, or the certificate has expired."
Packit 1fb8d4
	         "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
Packit 1fb8d4
	JNIEnv* env;
Packit 1fb8d4
	jboolean attached = jni_attach_thread(&env;;
Packit 1fb8d4
	jstring jstr0 = (*env)->NewStringUTF(env, common_name);
Packit 1fb8d4
	jstring jstr1 = (*env)->NewStringUTF(env, subject);
Packit 1fb8d4
	jstring jstr2 = (*env)->NewStringUTF(env, issuer);
Packit 1fb8d4
	jstring jstr3 = (*env)->NewStringUTF(env, fingerprint);
Packit Service 5a9772
	jint res = freerdp_callback_int_result(
Packit Service 5a9772
	    "OnVerifyCertificate",
Packit Service 5a9772
	    "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I",
Packit Service 5a9772
	    (jlong)instance, jstr0, jstr1, jstr2, jstr3, host_mismatch);
Packit 1fb8d4
Packit 1fb8d4
	if (attached == JNI_TRUE)
Packit 1fb8d4
		jni_detach_thread();
Packit 1fb8d4
Packit 1fb8d4
	return res;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static DWORD android_verify_changed_certificate(freerdp* instance, const char* common_name,
Packit Service 5a9772
                                                const char* subject, const char* issuer,
Packit Service 5a9772
                                                const char* new_fingerprint,
Packit Service 5a9772
                                                const char* old_subject, const char* old_issuer,
Packit Service 5a9772
                                                const char* old_fingerprint)
Packit 1fb8d4
{
Packit 1fb8d4
	JNIEnv* env;
Packit 1fb8d4
	jboolean attached = jni_attach_thread(&env;;
Packit 1fb8d4
	jstring jstr0 = (*env)->NewStringUTF(env, common_name);
Packit 1fb8d4
	jstring jstr1 = (*env)->NewStringUTF(env, subject);
Packit 1fb8d4
	jstring jstr2 = (*env)->NewStringUTF(env, issuer);
Packit 1fb8d4
	jstring jstr3 = (*env)->NewStringUTF(env, new_fingerprint);
Packit 1fb8d4
	jstring jstr4 = (*env)->NewStringUTF(env, old_subject);
Packit 1fb8d4
	jstring jstr5 = (*env)->NewStringUTF(env, old_issuer);
Packit 1fb8d4
	jstring jstr6 = (*env)->NewStringUTF(env, old_fingerprint);
Packit Service 5a9772
	jint res = freerdp_callback_int_result(
Packit Service 5a9772
	    "OnVerifyChangedCertificate",
Packit Service 5a9772
	    "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;"
Packit Service 5a9772
	    "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
Packit Service 5a9772
	    (jlong)instance, jstr0, jstr1, jstr2, jstr3, jstr4, jstr5, jstr6);
Packit 1fb8d4
Packit 1fb8d4
	if (attached == JNI_TRUE)
Packit 1fb8d4
		jni_detach_thread();
Packit 1fb8d4
Packit 1fb8d4
	return res;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI jni_input_thread(LPVOID arg)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE event[2];
Packit 1fb8d4
	wMessageQueue* queue;
Packit Service 5a9772
	freerdp* instance = (freerdp*)arg;
Packit 1fb8d4
	WLog_DBG(TAG, "input_thread Start.");
Packit 1fb8d4
Packit 1fb8d4
	if (!(queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE)))
Packit 1fb8d4
		goto disconnect;
Packit 1fb8d4
Packit 1fb8d4
	if (!(event[0] = android_get_handle(instance)))
Packit 1fb8d4
		goto disconnect;
Packit 1fb8d4
Packit Service 5a9772
	if (!(event[1] = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE)))
Packit 1fb8d4
		goto disconnect;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		DWORD rc = WaitForMultipleObjects(2, event, FALSE, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		if ((rc < WAIT_OBJECT_0) || (rc > WAIT_OBJECT_0 + 1))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		if (rc == WAIT_OBJECT_0 + 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			wMessage msg;
Packit 1fb8d4
			MessageQueue_Peek(queue, &msg, FALSE);
Packit 1fb8d4
Packit 1fb8d4
			if (msg.id == WMQ_QUIT)
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (android_check_handle(instance) != TRUE)
Packit 1fb8d4
			break;
Packit Service 5a9772
	} while (1);
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "input_thread Quit.");
Packit 1fb8d4
disconnect:
Packit 1fb8d4
	MessageQueue_PostQuit(queue, 0);
Packit 1fb8d4
	ExitThread(0);
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int android_freerdp_run(freerdp* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD count;
Packit 1fb8d4
	DWORD status = WAIT_FAILED;
Packit 1fb8d4
	HANDLE handles[64];
Packit 1fb8d4
	HANDLE inputEvent = NULL;
Packit 1fb8d4
	HANDLE inputThread = NULL;
Packit 1fb8d4
	const rdpSettings* settings = instance->context->settings;
Packit 1fb8d4
	rdpContext* context = instance->context;
Packit 1fb8d4
	BOOL async_input = settings->AsyncInput;
Packit Service 5a9772
	WLog_DBG(TAG, "AsyncInput=%" PRIu8 "", settings->AsyncInput);
Packit 1fb8d4
Packit 1fb8d4
	if (async_input)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(inputThread = CreateThread(NULL, 0, jni_input_thread, instance, 0, NULL)))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "async input: failed to create input thread");
Packit 1fb8d4
			goto disconnect;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		inputEvent = android_get_handle(instance);
Packit 1fb8d4
Packit 1fb8d4
	while (!freerdp_shall_disconnect(instance))
Packit 1fb8d4
	{
Packit 1fb8d4
		DWORD tmp;
Packit 1fb8d4
		count = 0;
Packit 1fb8d4
Packit 1fb8d4
		if (inputThread)
Packit 1fb8d4
			handles[count++] = inputThread;
Packit 1fb8d4
		else
Packit 1fb8d4
			handles[count++] = inputEvent;
Packit 1fb8d4
Packit 1fb8d4
		tmp = freerdp_get_event_handles(context, &handles[count], 64 - count);
Packit 1fb8d4
Packit 1fb8d4
		if (tmp == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "freerdp_get_event_handles failed");
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		count += tmp;
Packit 1fb8d4
		status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		if ((status == WAIT_FAILED))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "WaitForMultipleObjects failed with %" PRIu32 " [%08lX]", status,
Packit Service 5a9772
			         GetLastError());
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!freerdp_check_event_handles(context))
Packit 1fb8d4
		{
Packit 1fb8d4
			/* TODO: Auto reconnect
Packit 1fb8d4
			if (xf_auto_reconnect(instance))
Packit Service 5a9772
			    continue;
Packit Service 5a9772
			    */
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
Packit 1fb8d4
			status = GetLastError();
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (freerdp_shall_disconnect(instance))
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		if (!async_input)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (android_check_handle(instance) != TRUE)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Failed to check android file descriptor");
Packit 1fb8d4
				status = GetLastError();
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
disconnect:
Packit 1fb8d4
	WLog_INFO(TAG, "Prepare shutdown...");
Packit 1fb8d4
Packit 1fb8d4
	if (async_input && inputThread)
Packit 1fb8d4
	{
Packit Service 5a9772
		wMessageQueue* input_queue =
Packit Service 5a9772
		    freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
Packit Service 5a9772
		MessageQueue_PostQuit(input_queue, 0);
Packit 1fb8d4
		WaitForSingleObject(inputThread, INFINITE);
Packit 1fb8d4
		CloseHandle(inputThread);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI android_thread_func(LPVOID param)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD status = ERROR_BAD_ARGUMENTS;
Packit 1fb8d4
	freerdp* instance = param;
Packit 1fb8d4
	WLog_DBG(TAG, "Start...");
Packit 1fb8d4
Packit 1fb8d4
	if (!instance || !instance->context)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	if (freerdp_client_start(instance->context) != CHANNEL_RC_OK)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "Connect...");
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_connect(instance))
Packit 1fb8d4
		status = GetLastError();
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		status = android_freerdp_run(instance);
Packit 1fb8d4
		WLog_DBG(TAG, "Disonnect...");
Packit 1fb8d4
Packit 1fb8d4
		if (!freerdp_disconnect(instance))
Packit 1fb8d4
			status = GetLastError();
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "Stop...");
Packit 1fb8d4
Packit 1fb8d4
	if (freerdp_client_stop(instance->context) != CHANNEL_RC_OK)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
fail:
Packit Service 5a9772
	WLog_DBG(TAG, "Session ended with %08" PRIX32 "", status);
Packit 1fb8d4
Packit 1fb8d4
	if (status == CHANNEL_RC_OK)
Packit 1fb8d4
		freerdp_callback("OnDisconnected", "(J)V", (jlong)instance);
Packit 1fb8d4
	else
Packit 1fb8d4
		freerdp_callback("OnConnectionFailure", "(J)V", (jlong)instance);
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "Quit.");
Packit 1fb8d4
	ExitThread(status);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL android_client_new(freerdp* instance, rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!instance || !context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_event_queue_init(instance))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	instance->PreConnect = android_pre_connect;
Packit 1fb8d4
	instance->PostConnect = android_post_connect;
Packit 1fb8d4
	instance->PostDisconnect = android_post_disconnect;
Packit 1fb8d4
	instance->Authenticate = android_authenticate;
Packit 1fb8d4
	instance->GatewayAuthenticate = android_gw_authenticate;
Packit 1fb8d4
	instance->VerifyCertificate = android_verify_certificate;
Packit 1fb8d4
	instance->VerifyChangedCertificate = android_verify_changed_certificate;
Packit 1fb8d4
	instance->LogonErrorInfo = NULL;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void android_client_free(freerdp* instance, rdpContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	android_event_queue_uninit(instance);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
Packit 1fb8d4
	pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
Packit 1fb8d4
	pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
Packit 1fb8d4
	pEntryPoints->GlobalInit = NULL;
Packit 1fb8d4
	pEntryPoints->GlobalUninit = NULL;
Packit 1fb8d4
	pEntryPoints->ContextSize = sizeof(androidContext);
Packit 1fb8d4
	pEntryPoints->ClientNew = android_client_new;
Packit 1fb8d4
	pEntryPoints->ClientFree = android_client_free;
Packit 1fb8d4
	pEntryPoints->ClientStart = NULL;
Packit 1fb8d4
	pEntryPoints->ClientStop = NULL;
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jlong JNICALL jni_freerdp_new(JNIEnv* env, jclass cls, jobject context)
Packit 1fb8d4
{
Packit 1fb8d4
	jclass contextClass;
Packit 1fb8d4
	jclass fileClass;
Packit 1fb8d4
	jobject filesDirObj;
Packit 1fb8d4
	jmethodID getFilesDirID;
Packit 1fb8d4
	jmethodID getAbsolutePathID;
Packit 1fb8d4
	jstring path;
Packit 1fb8d4
	const char* raw;
Packit 1fb8d4
	char* envStr;
Packit 1fb8d4
	RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
Packit 1fb8d4
	rdpContext* ctx;
Packit 1fb8d4
#if defined(WITH_GPROF)
Packit 1fb8d4
	setenv("CPUPROFILE_FREQUENCY", "200", 1);
Packit 1fb8d4
	monstartup("libfreerdp-android.so");
Packit 1fb8d4
#endif
Packit 1fb8d4
	contextClass = (*env)->FindClass(env, JAVA_CONTEXT_CLASS);
Packit 1fb8d4
	fileClass = (*env)->FindClass(env, JAVA_FILE_CLASS);
Packit 1fb8d4
Packit 1fb8d4
	if (!contextClass || !fileClass)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "Failed to load class references %s=%p, %s=%p", JAVA_CONTEXT_CLASS,
Packit Service 5a9772
		           (void*)contextClass, JAVA_FILE_CLASS, (void*)fileClass);
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	getFilesDirID =
Packit Service 5a9772
	    (*env)->GetMethodID(env, contextClass, "getFilesDir", "()L" JAVA_FILE_CLASS ";");
Packit 1fb8d4
Packit 1fb8d4
	if (!getFilesDirID)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "Failed to find method ID getFilesDir ()L" JAVA_FILE_CLASS ";");
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	getAbsolutePathID =
Packit Service 5a9772
	    (*env)->GetMethodID(env, fileClass, "getAbsolutePath", "()Ljava/lang/String;");
Packit 1fb8d4
Packit 1fb8d4
	if (!getAbsolutePathID)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "Failed to find method ID getAbsolutePath ()Ljava/lang/String;");
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	filesDirObj = (*env)->CallObjectMethod(env, context, getFilesDirID);
Packit 1fb8d4
Packit 1fb8d4
	if (!filesDirObj)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "Failed to call getFilesDir");
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	path = (*env)->CallObjectMethod(env, filesDirObj, getAbsolutePathID);
Packit 1fb8d4
Packit 1fb8d4
	if (!path)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "Failed to call getAbsolutePath");
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	raw = (*env)->GetStringUTFChars(env, path, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (!raw)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "Failed to get C string from java string");
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	envStr = _strdup(raw);
Packit 1fb8d4
	(*env)->ReleaseStringUTFChars(env, path, raw);
Packit 1fb8d4
Packit 1fb8d4
	if (!envStr)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "_strdup(%s) failed", raw);
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (setenv("HOME", _strdup(envStr), 1) != 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "Failed to set environemnt HOME=%s %s [%d]", env, strerror(errno), errno);
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	RdpClientEntry(&clientEntryPoints);
Packit 1fb8d4
	ctx = freerdp_client_context_new(&clientEntryPoints);
Packit 1fb8d4
Packit 1fb8d4
	if (!ctx)
Packit 1fb8d4
		return (jlong)NULL;
Packit 1fb8d4
Packit Service 5a9772
	return (jlong)ctx->instance;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void JNICALL jni_freerdp_free(JNIEnv* env, jclass cls, jlong instance)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
Packit 1fb8d4
	if (inst)
Packit 1fb8d4
		freerdp_client_context_free(inst->context);
Packit 1fb8d4
Packit 1fb8d4
#if defined(WITH_GPROF)
Packit 1fb8d4
	moncleanup();
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jstring JNICALL jni_freerdp_get_last_error_string(JNIEnv* env, jclass cls, jlong instance)
Packit Service 5a9772
{
Packit Service 5a9772
	freerdp* inst = (freerdp*)instance;
Packit Service 5a9772
Packit Service 5a9772
	if (!inst || !inst->context)
Packit Service 5a9772
		return (*env)->NewStringUTF(env, "");
Packit Service 5a9772
Packit Service 5a9772
	return (*env)->NewStringUTF(
Packit Service 5a9772
	    env, freerdp_get_last_error_string(freerdp_get_last_error(inst->context)));
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_parse_arguments(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                    jobjectArray arguments)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
	int i, count;
Packit 1fb8d4
	char** argv;
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
Packit 1fb8d4
	if (!inst || !inst->context)
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	count = (*env)->GetArrayLength(env, arguments);
Packit 1fb8d4
	argv = calloc(count, sizeof(char*));
Packit 1fb8d4
Packit 1fb8d4
	if (!argv)
Packit 1fb8d4
		return JNI_TRUE;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		jstring str = (jstring)(*env)->GetObjectArrayElement(env, arguments, i);
Packit 1fb8d4
		const char* raw = (*env)->GetStringUTFChars(env, str, 0);
Packit 1fb8d4
		argv[i] = _strdup(raw);
Packit 1fb8d4
		(*env)->ReleaseStringUTFChars(env, str, raw);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	status = freerdp_client_settings_parse_command_line(inst->settings, count, argv, FALSE);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < count; i++)
Packit 1fb8d4
		free(argv[i]);
Packit 1fb8d4
Packit 1fb8d4
	free(argv);
Packit 1fb8d4
	return (status == 0) ? JNI_TRUE : JNI_FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_connect(JNIEnv* env, jclass cls, jlong instance)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
	androidContext* ctx;
Packit 1fb8d4
Packit 1fb8d4
	if (!inst || !inst->context)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls,
Packit Service 5a9772
		           instance);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ctx = (androidContext*)inst->context;
Packit 1fb8d4
Packit Service 5a9772
	if (!(ctx->thread = CreateThread(NULL, 0, android_thread_func, inst, 0, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return JNI_TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_disconnect(JNIEnv* env, jclass cls, jlong instance)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
	androidContext* ctx;
Packit 1fb8d4
	ANDROID_EVENT* event;
Packit 1fb8d4
Packit 1fb8d4
	if (!inst || !inst->context || !cls || !env)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls,
Packit Service 5a9772
		           instance);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ctx = (androidContext*)inst->context;
Packit 1fb8d4
	event = (ANDROID_EVENT*)android_event_disconnect_new();
Packit 1fb8d4
Packit 1fb8d4
	if (!event)
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_push_event(inst, event))
Packit 1fb8d4
	{
Packit 1fb8d4
		android_event_free((ANDROID_EVENT*)event);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_abort_connect(inst))
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return JNI_TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_update_graphics(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                    jobject bitmap, jint x, jint y, jint width,
Packit Service 5a9772
                                                    jint height)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 DstFormat;
Packit 1fb8d4
	jboolean rc;
Packit 1fb8d4
	int ret;
Packit 1fb8d4
	void* pixels;
Packit 1fb8d4
	AndroidBitmapInfo info;
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
	rdpGdi* gdi;
Packit 1fb8d4
Packit 1fb8d4
	if (!env || !cls || !inst)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls,
Packit Service 5a9772
		           instance);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	gdi = inst->context->gdi;
Packit 1fb8d4
Packit 1fb8d4
	if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "AndroidBitmap_getInfo() failed ! error=%d", ret);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "AndroidBitmap_lockPixels() failed ! error=%d", ret);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rc = JNI_TRUE;
Packit 1fb8d4
Packit 1fb8d4
	switch (info.format)
Packit 1fb8d4
	{
Packit 1fb8d4
		case ANDROID_BITMAP_FORMAT_RGBA_8888:
Packit 1fb8d4
			DstFormat = PIXEL_FORMAT_RGBA32;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ANDROID_BITMAP_FORMAT_RGB_565:
Packit 1fb8d4
			DstFormat = PIXEL_FORMAT_RGB16;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ANDROID_BITMAP_FORMAT_RGBA_4444:
Packit 1fb8d4
		case ANDROID_BITMAP_FORMAT_A_8:
Packit 1fb8d4
		case ANDROID_BITMAP_FORMAT_NONE:
Packit 1fb8d4
		default:
Packit 1fb8d4
			rc = JNI_FALSE;
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (rc)
Packit 1fb8d4
	{
Packit 1fb8d4
		rc = freerdp_image_copy(pixels, DstFormat, info.stride, x, y, width, height,
Packit 1fb8d4
		                        gdi->primary_buffer, gdi->dstFormat, gdi->stride, x, y,
Packit 1fb8d4
		                        &gdi->palette, FREERDP_FLIP_NONE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((ret = AndroidBitmap_unlockPixels(env, bitmap)) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "AndroidBitmap_unlockPixels() failed ! error=%d", ret);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_send_key_event(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                   jint keycode, jboolean down)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD scancode;
Packit 1fb8d4
	ANDROID_EVENT* event;
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit 1fb8d4
	scancode = GetVirtualScanCodeFromVirtualKeyCode(keycode, 4);
Packit 1fb8d4
	int flags = (down == JNI_TRUE) ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE;
Packit 1fb8d4
	flags |= (scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0;
Packit Service 5a9772
	event = (ANDROID_EVENT*)android_event_key_new(flags, scancode & 0xFF);
Packit 1fb8d4
Packit 1fb8d4
	if (!event)
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_push_event(inst, event))
Packit 1fb8d4
	{
Packit 1fb8d4
		android_event_free(event);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	WLog_DBG(TAG, "send_key_event: %" PRIu32 ", %d", scancode, flags);
Packit 1fb8d4
	return JNI_TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_send_unicodekey_event(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                          jint keycode, jboolean down)
Packit 1fb8d4
{
Packit 1fb8d4
	ANDROID_EVENT* event;
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit Service 5a9772
	UINT16 flags = (down == JNI_TRUE) ? 0 : KBD_FLAGS_RELEASE;
Packit Service 5a9772
	event = (ANDROID_EVENT*)android_event_unicodekey_new(flags, keycode);
Packit 1fb8d4
Packit 1fb8d4
	if (!event)
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_push_event(inst, event))
Packit 1fb8d4
	{
Packit 1fb8d4
		android_event_free(event);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "send_unicodekey_event: %d", keycode);
Packit 1fb8d4
	return JNI_TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_send_cursor_event(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                      jint x, jint y, jint flags)
Packit 1fb8d4
{
Packit 1fb8d4
	ANDROID_EVENT* event;
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit Service 5a9772
	event = (ANDROID_EVENT*)android_event_cursor_new(flags, x, y);
Packit 1fb8d4
Packit 1fb8d4
	if (!event)
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_push_event(inst, event))
Packit 1fb8d4
	{
Packit 1fb8d4
		android_event_free(event);
Packit 1fb8d4
		return JNI_FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "send_cursor_event: (%d, %d), %d", x, y, flags);
Packit 1fb8d4
	return JNI_TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv* env, jclass cls, jlong instance,
Packit Service 5a9772
                                                        jstring jdata)
Packit 1fb8d4
{
Packit 1fb8d4
	ANDROID_EVENT* event;
Packit 1fb8d4
	freerdp* inst = (freerdp*)instance;
Packit Service 5a9772
	const jbyte* data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, NULL) : NULL;
Packit 1fb8d4
	int data_length = data ? strlen(data) : 0;
Packit Service 5a9772
	jboolean ret = JNI_FALSE;
Packit Service 5a9772
	event = (ANDROID_EVENT*)android_event_clipboard_new((void*)data, data_length);
Packit 1fb8d4
Packit 1fb8d4
	if (!event)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	if (!android_push_event(inst, event))
Packit 1fb8d4
	{
Packit 1fb8d4
		android_event_free(event);
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "send_clipboard_data: (%s)", data);
Packit 1fb8d4
	ret = JNI_TRUE;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
Packit 1fb8d4
	if (data)
Packit 1fb8d4
		(*env)->ReleaseStringUTFChars(env, jdata, data);
Packit 1fb8d4
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jstring JNICALL jni_freerdp_get_jni_version(JNIEnv* env, jclass cls)
Packit 1fb8d4
{
Packit 1fb8d4
	return (*env)->NewStringUTF(env, FREERDP_JNI_VERSION);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jstring JNICALL jni_freerdp_get_version(JNIEnv* env, jclass cls)
Packit 1fb8d4
{
Packit 1fb8d4
	return (*env)->NewStringUTF(env, freerdp_get_version_string());
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jstring JNICALL jni_freerdp_get_build_date(JNIEnv* env, jclass cls)
Packit 1fb8d4
{
Packit 1fb8d4
	return (*env)->NewStringUTF(env, freerdp_get_build_date());
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jstring JNICALL jni_freerdp_get_build_revision(JNIEnv* env, jclass cls)
Packit 1fb8d4
{
Packit 1fb8d4
	return (*env)->NewStringUTF(env, freerdp_get_build_revision());
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static jstring JNICALL jni_freerdp_get_build_config(JNIEnv* env, jclass cls)
Packit 1fb8d4
{
Packit 1fb8d4
	return (*env)->NewStringUTF(env, freerdp_get_build_config());
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static JNINativeMethod methods[] = {
Packit Service 5a9772
	{ "freerdp_get_jni_version", "()Ljava/lang/String;", &jni_freerdp_get_jni_version },
Packit Service 5a9772
	{ "freerdp_get_version", "()Ljava/lang/String;", &jni_freerdp_get_version },
Packit Service 5a9772
	{ "freerdp_get_build_date", "()Ljava/lang/String;", &jni_freerdp_get_build_date },
Packit Service 5a9772
	{ "freerdp_get_build_revision", "()Ljava/lang/String;", &jni_freerdp_get_build_revision },
Packit Service 5a9772
	{ "freerdp_get_build_config", "()Ljava/lang/String;", &jni_freerdp_get_build_config },
Packit Service 5a9772
	{ "freerdp_get_last_error_string", "(J)Ljava/lang/String;",
Packit Service 5a9772
	  &jni_freerdp_get_last_error_string },
Packit Service 5a9772
	{ "freerdp_new", "(Landroid/content/Context;)J", &jni_freerdp_new },
Packit Service 5a9772
	{ "freerdp_free", "(J)V", &jni_freerdp_free },
Packit Service 5a9772
	{ "freerdp_parse_arguments", "(J[Ljava/lang/String;)Z", &jni_freerdp_parse_arguments },
Packit Service 5a9772
	{ "freerdp_connect", "(J)Z", &jni_freerdp_connect },
Packit Service 5a9772
	{ "freerdp_disconnect", "(J)Z", &jni_freerdp_disconnect },
Packit Service 5a9772
	{ "freerdp_update_graphics", "(JLandroid/graphics/Bitmap;IIII)Z",
Packit Service 5a9772
	  &jni_freerdp_update_graphics },
Packit Service 5a9772
	{ "freerdp_send_cursor_event", "(JIII)Z", &jni_freerdp_send_cursor_event },
Packit Service 5a9772
	{ "freerdp_send_key_event", "(JIZ)Z", &jni_freerdp_send_key_event },
Packit Service 5a9772
	{ "freerdp_send_unicodekey_event", "(JIZ)Z", &jni_freerdp_send_unicodekey_event },
Packit Service 5a9772
	{ "freerdp_send_clipboard_data", "(JLjava/lang/String;)Z", &jni_freerdp_send_clipboard_data }
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static jclass gJavaActivityClass = NULL;
Packit 1fb8d4
Packit 1fb8d4
jint JNI_OnLoad(JavaVM* vm, void* reserved)
Packit 1fb8d4
{
Packit 1fb8d4
	JNIEnv* env;
Packit 1fb8d4
	setlocale(LC_ALL, "");
Packit 1fb8d4
	WLog_DBG(TAG, "Setting up JNI environement...");
Packit 1fb8d4
Packit 1fb8d4
	/*
Packit Service 5a9772
	    if (freerdp_handle_signals() != 0)
Packit Service 5a9772
	    {
Packit Service 5a9772
	        WLog_FATAL(TAG, "Failed to register signal handler");
Packit Service 5a9772
	        return -1;
Packit Service 5a9772
	    }
Packit 1fb8d4
	*/
Packit 1fb8d4
	if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "Failed to get the environment");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	// Get SBCEngine activity class
Packit 1fb8d4
	jclass activityClass = (*env)->FindClass(env, JAVA_LIBFREERDP_CLASS);
Packit 1fb8d4
Packit 1fb8d4
	if (!activityClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "failed to get %s class reference", JAVA_LIBFREERDP_CLASS);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	// Register methods with env->RegisterNatives.
Packit Service 5a9772
	(*env)->RegisterNatives(env, activityClass, methods, sizeof(methods) / sizeof(methods[0]));
Packit 1fb8d4
	/* create global reference for class */
Packit 1fb8d4
	gJavaActivityClass = (*env)->NewGlobalRef(env, activityClass);
Packit 1fb8d4
	g_JavaVm = vm;
Packit 1fb8d4
	return init_callback_environment(vm, env);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
Packit 1fb8d4
{
Packit 1fb8d4
	JNIEnv* env;
Packit 1fb8d4
	WLog_DBG(TAG, "Tearing down JNI environement...");
Packit 1fb8d4
Packit 1fb8d4
	if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_FATAL(TAG, "Failed to get the environment");
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	(*env)->UnregisterNatives(env, gJavaActivityClass);
Packit 1fb8d4
Packit 1fb8d4
	if (gJavaActivityClass)
Packit 1fb8d4
		(*env)->DeleteGlobalRef(env, gJavaActivityClass);
Packit 1fb8d4
}