mirror of https://github.com/FreeRDP/FreeRDP
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b39ae79749
|
@ -13,6 +13,8 @@ CPackConfig.cmake
|
|||
CPackSourceConfig.cmake
|
||||
DartConfiguration.tcl
|
||||
_CPack_Packages
|
||||
external/*
|
||||
!external/README
|
||||
|
||||
# Packages
|
||||
*.zip
|
||||
|
|
|
@ -60,13 +60,13 @@ else()
|
|||
endif()
|
||||
|
||||
# Allow to search the host machine for git
|
||||
if(ANDROID)
|
||||
if(ANDROID OR IOS)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER, BOTH)
|
||||
endif(ANDROID)
|
||||
endif(ANDROID OR IOS)
|
||||
include(GetGitRevisionDescription)
|
||||
if(ANDROID)
|
||||
if(ANDROID OR IOS)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER, ONLY)
|
||||
endif(ANDROID)
|
||||
endif(ANDROID OR IOS)
|
||||
|
||||
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
|
||||
message(STATUS "Git Revision ${GIT_REVISION}")
|
||||
|
@ -74,14 +74,13 @@ message(STATUS "Git Revision ${GIT_REVISION}")
|
|||
# Turn on solution folders (2.8.4+)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
|
||||
# Default to release build type
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BUILD_SHARED_LIBS)
|
||||
if(ANDROID)
|
||||
if(ANDROID OR IOS)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
else()
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
|
@ -167,6 +166,10 @@ if(MSVC)
|
|||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -isysroot ${CMAKE_IOS_SDK_ROOT}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_EXPORTS")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFREERDP_EXPORTS")
|
||||
|
||||
|
@ -183,14 +186,21 @@ check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
|
|||
|
||||
# Mac OS X
|
||||
if(APPLE)
|
||||
if(IS_DIRECTORY /opt/local/include)
|
||||
include_directories(/opt/local/include)
|
||||
link_directories(/opt/local/lib)
|
||||
endif()
|
||||
if(WITH_CLANG)
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.4")
|
||||
if(IOS)
|
||||
if (NOT FREERDP_IOS_EXTERNAL_SSL_PATH)
|
||||
message(STATUS "FREERDP_IOS_EXTERNAL_SSL_PATH not set! Required if openssl is not found in the iOS SDK (which usually isn't")
|
||||
endif()
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_IOS_EXTERNAL_SSL_PATH})
|
||||
else()
|
||||
if(IS_DIRECTORY /opt/local/include)
|
||||
include_directories(/opt/local/include)
|
||||
link_directories(/opt/local/lib)
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.4")
|
||||
endif()
|
||||
if(WITH_CLANG)
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Android
|
||||
|
@ -272,6 +282,14 @@ endif()
|
|||
if(APPLE)
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||
if(IOS)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
|
@ -285,17 +303,6 @@ if(ANDROID)
|
|||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
|
||||
find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION})
|
||||
find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION})
|
||||
|
||||
|
|
|
@ -685,9 +685,9 @@ void drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, char*
|
|||
* We cannot enter paths like c:\ because : is an arg separator
|
||||
* thus, paths are entered as c+\ and the + is substituted here
|
||||
*/
|
||||
if ( path[1] == '+' )
|
||||
if (path[1] == '+')
|
||||
{
|
||||
if ( (path[0]>='a' && path[0]<='z') || (path[0]>='A' && path[0]<='Z') )
|
||||
if ((path[0]>='a' && path[0]<='z') || (path[0]>='A' && path[0]<='Z'))
|
||||
{
|
||||
path[1] = ':';
|
||||
}
|
||||
|
@ -732,8 +732,6 @@ void drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, char*
|
|||
|
||||
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
char* name;
|
||||
char* path;
|
||||
RDPDR_DRIVE* drive;
|
||||
#ifdef WIN32
|
||||
char* dev;
|
||||
|
@ -742,20 +740,42 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||
#endif
|
||||
|
||||
drive = (RDPDR_DRIVE*) pEntryPoints->device;
|
||||
name = drive->Name;
|
||||
path = drive->Path;
|
||||
|
||||
#ifndef WIN32
|
||||
drive_register_drive_path(pEntryPoints, name, path);
|
||||
|
||||
if (strcmp(drive->Path, "*") == 0)
|
||||
{
|
||||
/* all drives */
|
||||
|
||||
free(drive->Path);
|
||||
drive->Path = _strdup("/");
|
||||
}
|
||||
else if (strcmp(drive->Path, "%") == 0)
|
||||
{
|
||||
char* home_env = NULL;
|
||||
|
||||
/* home directory */
|
||||
|
||||
home_env = getenv("HOME");
|
||||
free(drive->Path);
|
||||
|
||||
if (home_env)
|
||||
drive->Path = _strdup(home_env);
|
||||
else
|
||||
drive->Path = _strdup("/");
|
||||
}
|
||||
|
||||
drive_register_drive_path(pEntryPoints, drive->Name, drive->Path);
|
||||
|
||||
#else
|
||||
/* Special case: path[0] == '*' -> export all drives */
|
||||
/* Special case: path[0] == '%' -> user home dir */
|
||||
if( path[0] == '%' )
|
||||
if (strcmp(drive->Path, "%") == 0)
|
||||
{
|
||||
_snprintf(buf, sizeof(buf), "%s\\", getenv("USERPROFILE"));
|
||||
drive_register_drive_path(pEntryPoints, name, _strdup(buf));
|
||||
drive_register_drive_path(pEntryPoints, drive->Name, _strdup(buf));
|
||||
}
|
||||
else if( path[0] == '*' )
|
||||
else if (strcmp(drive->Path, "*") == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -767,7 +787,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||
if (*dev > 'B')
|
||||
{
|
||||
/* Suppress disk drives A and B to avoid pesty messages */
|
||||
_snprintf(buf, sizeof(buf) - 4, "%s", name);
|
||||
_snprintf(buf, sizeof(buf) - 4, "%s", drive->Name);
|
||||
len = strlen(buf);
|
||||
buf[len] = '_';
|
||||
buf[len + 1] = dev[0];
|
||||
|
@ -779,7 +799,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||
}
|
||||
else
|
||||
{
|
||||
drive_register_drive_path(pEntryPoints, name, path);
|
||||
drive_register_drive_path(pEntryPoints, drive->Name, drive->Path);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ void rail_send_client_window_move_order(rdpRailOrder* rail_order);
|
|||
void rail_send_client_get_appid_req_order(rdpRailOrder* rail_order);
|
||||
void rail_send_client_langbar_info_order(rdpRailOrder* rail_order);
|
||||
|
||||
rdpRailOrder* rail_order_new();
|
||||
rdpRailOrder* rail_order_new(void);
|
||||
void rail_order_free(rdpRailOrder* rail_order);
|
||||
|
||||
#endif /* __RAIL_ORDERS_H */
|
||||
|
|
|
@ -62,7 +62,7 @@ struct _ISOCH_CALLBACK_QUEUE
|
|||
};
|
||||
|
||||
|
||||
ISOCH_CALLBACK_QUEUE* isoch_queue_new();
|
||||
ISOCH_CALLBACK_QUEUE* isoch_queue_new(void);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ struct _REQUEST_QUEUE
|
|||
};
|
||||
|
||||
|
||||
REQUEST_QUEUE* request_queue_new();
|
||||
REQUEST_QUEUE* request_queue_new(void);
|
||||
|
||||
|
||||
#endif /* __REQUEST_QUEUE_H */
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
iOS
|
|
@ -63,7 +63,7 @@ BOOL android_check_fds(freerdp * inst);
|
|||
ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancode);
|
||||
ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 key);
|
||||
ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y);
|
||||
ANDROID_EVENT* android_event_disconnect_new();
|
||||
ANDROID_EVENT* android_event_disconnect_new(void);
|
||||
void android_event_key_free(ANDROID_EVENT_KEY* event);
|
||||
void android_event_unicodekey_free(ANDROID_EVENT_KEY* event);
|
||||
void android_event_cursor_free(ANDROID_EVENT_CURSOR* event);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
jint init_callback_environment(JavaVM* vm);
|
||||
jboolean jni_attach_thread(JNIEnv** env);
|
||||
void jni_detach_thread();
|
||||
void jni_detach_thread(void);
|
||||
void freerdp_callback(const char * callback, const char * signature, ...);
|
||||
jboolean freerdp_callback_bool_result(const char * callback, const char * signature, ...);
|
||||
void tsxconnect_callback(const char * callback, const char * signature, ...);
|
||||
|
|
|
@ -35,8 +35,15 @@ if(WITH_X11)
|
|||
add_subdirectory(X11)
|
||||
endif()
|
||||
|
||||
if(APPLE AND (NOT IOS))
|
||||
add_subdirectory(Mac)
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/iOS")
|
||||
message(STATUS "Adding iOS client")
|
||||
add_subdirectory(iOS)
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(Mac)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "dfreerdp.h"
|
||||
|
||||
void df_keyboard_init();
|
||||
void df_keyboard_init(void);
|
||||
BOOL df_event_process(freerdp* instance, DFBEvent* event);
|
||||
|
||||
#endif /* __DF_EVENT_H */
|
||||
|
|
|
@ -15,5 +15,5 @@
|
|||
@property (assign) IBOutlet NSWindow *window;
|
||||
|
||||
|
||||
int rdp_connect();
|
||||
int rdp_connect(void);
|
||||
@end
|
||||
|
|
|
@ -99,7 +99,7 @@ void pointer_free(rdpContext* context, rdpPointer* pointer);
|
|||
void pointer_set(rdpContext* context, rdpPointer* pointer);
|
||||
void pointer_setNull(rdpContext* context);
|
||||
void pointer_setDefault(rdpContext* context);
|
||||
int rdp_connect();
|
||||
int rdp_connect(void);
|
||||
BOOL mac_pre_connect(freerdp *inst);
|
||||
BOOL mac_post_connect(freerdp *inst);
|
||||
void mac_context_new(freerdp *inst, rdpContext *context);
|
||||
|
@ -139,7 +139,7 @@ void mac_send_rail_client_event(rdpChannels *channels, UINT16 event_type, void *
|
|||
void mac_on_free_rail_client_event(RDP_EVENT* event);
|
||||
void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event);
|
||||
void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event);
|
||||
void mac_rail_enable_remoteapp_mode();
|
||||
void mac_rail_enable_remoteapp_mode(void);
|
||||
void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event);
|
||||
void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event);
|
||||
void apple_center_window(NSRect * r);
|
||||
|
|
|
@ -713,8 +713,7 @@ static BOOL xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target)
|
|||
unsigned long length, bytes_left, dummy;
|
||||
clipboardContext* cb = (clipboardContext*) xfi->clipboard_context;
|
||||
|
||||
if ((cb->request_index < 0) ||
|
||||
(cb->format_mappings[cb->request_index].target_format != target))
|
||||
if ((cb->request_index < 0) || (cb->format_mappings[cb->request_index].target_format != target))
|
||||
{
|
||||
DEBUG_X11_CLIPRDR("invalid target");
|
||||
xf_cliprdr_send_null_data_response(xfi);
|
||||
|
@ -1132,6 +1131,7 @@ BOOL xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent)
|
|||
{
|
||||
format = cb->format_mappings[i].format_id;
|
||||
alt_format = format;
|
||||
|
||||
if (format == CB_FORMAT_RAW)
|
||||
{
|
||||
if (XGetWindowProperty(xfi->display, xevent->xselectionrequest.requestor,
|
||||
|
@ -1146,7 +1146,9 @@ BOOL xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent)
|
|||
XFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_X11_CLIPRDR("provide format 0x%04x alt_format 0x%04x", format, alt_format);
|
||||
|
||||
if ((cb->data != 0) && (format == cb->data_format) && (alt_format == cb->data_alt_format))
|
||||
{
|
||||
/* Cached clipboard data available. Send it now */
|
||||
|
@ -1206,6 +1208,9 @@ BOOL xf_cliprdr_process_property_notify(xfInfo* xfi, XEvent* xevent)
|
|||
{
|
||||
clipboardContext* cb = (clipboardContext*) xfi->clipboard_context;
|
||||
|
||||
if (!cb)
|
||||
return TRUE;
|
||||
|
||||
if (xevent->xproperty.atom != cb->property_atom)
|
||||
return FALSE; /* Not cliprdr-related */
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ static BOOL xf_event_Expose(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
w = event->xexpose.width;
|
||||
h = event->xexpose.height;
|
||||
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ static BOOL xf_event_FocusIn(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
xfi->focused = TRUE;
|
||||
|
||||
if (xfi->mouse_active && (app != TRUE))
|
||||
if (xfi->mouse_active && (!app))
|
||||
XGrabKeyboard(xfi->display, xfi->window->handle, TRUE, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
|
||||
if (app)
|
||||
|
@ -397,9 +397,10 @@ static BOOL xf_event_FocusIn(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
if (window != NULL)
|
||||
xf_rail_adjust_position(xfi, window);
|
||||
}
|
||||
|
||||
xf_kbd_focus_in(xfi);
|
||||
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
xf_cliprdr_check_owner(xfi);
|
||||
|
||||
return TRUE;
|
||||
|
@ -466,7 +467,7 @@ static BOOL xf_event_ClientMessage(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_EnterNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
{
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
xfi->mouse_active = TRUE;
|
||||
|
||||
|
@ -497,7 +498,7 @@ static BOOL xf_event_EnterNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_LeaveNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
{
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
xfi->mouse_active = FALSE;
|
||||
XUngrabKeyboard(xfi->display, CurrentTime);
|
||||
|
@ -573,17 +574,14 @@ static BOOL xf_event_MapNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
rdpUpdate* update = xfi->instance->update;
|
||||
rdpRail* rail = ((rdpContext*) xfi->context)->rail;
|
||||
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
if (xfi->suppress_output == TRUE)
|
||||
{
|
||||
xfi->suppress_output = FALSE;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = xfi->width;
|
||||
rect.bottom = xfi->height;
|
||||
update->SuppressOutput((rdpContext*) xfi->context, 1, &rect);
|
||||
}
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = xfi->width;
|
||||
rect.bottom = xfi->height;
|
||||
|
||||
update->SuppressOutput((rdpContext*) xfi->context, 1, &rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -615,13 +613,9 @@ static BOOL xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
xf_kbd_release_all_keypress(xfi);
|
||||
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
if (xfi->suppress_output == FALSE)
|
||||
{
|
||||
xfi->suppress_output = TRUE;
|
||||
update->SuppressOutput((rdpContext*) xfi->context, 0, NULL);
|
||||
}
|
||||
update->SuppressOutput((rdpContext*) xfi->context, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -629,7 +623,7 @@ static BOOL xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
if (window != NULL)
|
||||
{
|
||||
xfWindow *xfw = (xfWindow*) window->extra;
|
||||
xfWindow* xfw = (xfWindow*) window->extra;
|
||||
xfw->is_mapped = FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -639,7 +633,7 @@ static BOOL xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_SelectionNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
{
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
if (xf_cliprdr_process_selection_notify(xfi, event))
|
||||
return TRUE;
|
||||
|
@ -650,7 +644,7 @@ static BOOL xf_event_SelectionNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_SelectionRequest(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
{
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
if (xf_cliprdr_process_selection_request(xfi, event))
|
||||
return TRUE;
|
||||
|
@ -661,7 +655,7 @@ static BOOL xf_event_SelectionRequest(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_SelectionClear(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
{
|
||||
if (app != TRUE)
|
||||
if (!app)
|
||||
{
|
||||
if (xf_cliprdr_process_selection_clear(xfi, event))
|
||||
return TRUE;
|
||||
|
@ -678,15 +672,14 @@ static BOOL xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
* ie. not using the buttons on the rail window itself
|
||||
*/
|
||||
|
||||
if (app == TRUE)
|
||||
if (app)
|
||||
{
|
||||
rdpWindow* window;
|
||||
|
||||
window = xf_rdpWindowFromWindow(xfi, event->xproperty.window);
|
||||
|
||||
if (window == NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((((Atom)event->xproperty.atom == xfi->_NET_WM_STATE) && (event->xproperty.state != PropertyDelete)) ||
|
||||
(((Atom)event->xproperty.atom == xfi->WM_STATE) && (event->xproperty.state != PropertyDelete)))
|
||||
|
@ -703,7 +696,8 @@ static BOOL xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
status = xf_GetWindowProperty(xfi, event->xproperty.window,
|
||||
xfi->_NET_WM_STATE, 12, &nitems, &bytes, &prop);
|
||||
|
||||
if (status != TRUE) {
|
||||
if (!status)
|
||||
{
|
||||
DEBUG_X11_LMS("No return _NET_WM_STATE, window is not maximized");
|
||||
}
|
||||
|
||||
|
@ -725,7 +719,8 @@ static BOOL xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
status = xf_GetWindowProperty(xfi, event->xproperty.window,
|
||||
xfi->WM_STATE, 1, &nitems, &bytes, &prop);
|
||||
|
||||
if (status != TRUE) {
|
||||
if (!status)
|
||||
{
|
||||
DEBUG_X11_LMS("No return WM_STATE, window is not minimized");
|
||||
}
|
||||
else
|
||||
|
@ -760,9 +755,7 @@ static BOOL xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (app != TRUE)
|
||||
else
|
||||
{
|
||||
if (xf_cliprdr_process_property_notify(xfi, event))
|
||||
return TRUE;
|
||||
|
@ -773,7 +766,7 @@ static BOOL xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
|||
|
||||
static BOOL xf_event_suppress_events(xfInfo *xfi, rdpWindow *window, XEvent*event)
|
||||
{
|
||||
if (! xfi->remote_app)
|
||||
if (!xfi->remote_app)
|
||||
return FALSE;
|
||||
|
||||
switch (xfi->window->local_move.state)
|
||||
|
@ -866,7 +859,7 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
|
|||
if (window)
|
||||
{
|
||||
/* Update "current" window for cursor change orders */
|
||||
xfi->window = (xfWindow *) window->extra;
|
||||
xfi->window = (xfWindow*) window->extra;
|
||||
|
||||
if (xf_event_suppress_events(xfi, window, event))
|
||||
return TRUE;
|
||||
|
@ -968,5 +961,7 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
|
|||
break;
|
||||
}
|
||||
|
||||
XSync(xfi->display, FALSE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include "xf_gdi.h"
|
||||
|
||||
static UINT8 GDI_BS_HACHTED_PATTERNS[] =
|
||||
static UINT8 GDI_BS_HATCHED_PATTERNS[] =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */
|
||||
0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_VERTICAL */
|
||||
|
@ -267,11 +267,11 @@ void xf_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette)
|
|||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
CopyMemory(xfi->clrconv->palette, palette, sizeof(rdpPalette));
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
|
||||
|
@ -279,7 +279,7 @@ void xf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
|
|||
XRectangle clip;
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (bounds != NULL)
|
||||
{
|
||||
|
@ -294,14 +294,14 @@ void xf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds)
|
|||
XSetClipMask(xfi->display, xfi->gc, None);
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
|
||||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_set_rop3(xfi, gdi_rop3_code(dstblt->bRop));
|
||||
|
||||
|
@ -312,18 +312,12 @@ void xf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
|
||||
dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
|
||||
}
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
||||
|
@ -335,7 +329,7 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
brush = &patblt->brush;
|
||||
xf_set_rop3(xfi, gdi_rop3_code(patblt->bRop));
|
||||
|
@ -353,7 +347,7 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
|||
}
|
||||
else if (brush->style == GDI_BS_HATCHED)
|
||||
{
|
||||
pattern = xf_mono_bitmap_new(xfi, 8, 8, GDI_BS_HACHTED_PATTERNS + 8 * brush->hatch);
|
||||
pattern = xf_mono_bitmap_new(xfi, 8, 8, GDI_BS_HATCHED_PATTERNS + 8 * brush->hatch);
|
||||
|
||||
XSetForeground(xfi->display, xfi->gc, backColor);
|
||||
XSetBackground(xfi->display, xfi->gc, foreColor);
|
||||
|
@ -406,27 +400,19 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, patblt->nLeftRect, patblt->nTopRect,
|
||||
patblt->nWidth, patblt->nHeight, patblt->nLeftRect, patblt->nTopRect);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
|
||||
}
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
|
||||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_set_rop3(xfi, gdi_rop3_code(scrblt->bRop));
|
||||
|
||||
|
@ -435,29 +421,12 @@ void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
if (xfi->unobscured)
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->drawable, xfi->drawable, xfi->gc,
|
||||
scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight,
|
||||
scrblt->nLeftRect, scrblt->nTopRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
|
||||
scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight,
|
||||
scrblt->nLeftRect, scrblt->nTopRect);
|
||||
}
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
|
||||
}
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
|
||||
|
@ -466,7 +435,7 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
color = freerdp_color_convert_var(opaque_rect->color, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
||||
|
@ -480,17 +449,11 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
|
||||
opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect,
|
||||
opaque_rect->nWidth, opaque_rect->nHeight);
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
|
||||
|
@ -501,7 +464,7 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
color = freerdp_color_convert_var(multi_opaque_rect->color, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
||||
|
@ -519,17 +482,11 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
|
||||
rectangle->left, rectangle->top, rectangle->width, rectangle->height);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, rectangle->left, rectangle->top, rectangle->width, rectangle->height);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_draw_nine_grid(rdpContext* context, DRAW_NINE_GRID_ORDER* draw_nine_grid)
|
||||
|
@ -543,7 +500,7 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_set_rop2(xfi, line_to->bRop2);
|
||||
color = freerdp_color_convert_var(line_to->penColor, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
@ -558,12 +515,6 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
|
|||
{
|
||||
int width, height;
|
||||
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XDrawLine(xfi->display, xfi->drawable, xfi->gc,
|
||||
line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd);
|
||||
}
|
||||
|
||||
width = line_to->nXStart - line_to->nXEnd;
|
||||
height = line_to->nYStart - line_to->nYEnd;
|
||||
|
||||
|
@ -579,7 +530,7 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
|
|||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
||||
|
@ -595,7 +546,7 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_set_rop2(xfi, polyline->bRop2);
|
||||
color = freerdp_color_convert_var(polyline->penColor, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
@ -619,9 +570,6 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
XDrawLines(xfi->display, xfi->drawable, xfi->gc, points, npoints, CoordModePrevious);
|
||||
|
||||
x1 = points[0].x;
|
||||
y1 = points[0].y;
|
||||
|
||||
|
@ -646,7 +594,7 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
|||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
free(points);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
|
||||
|
@ -654,7 +602,7 @@ void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
|
|||
xfBitmap* bitmap;
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
bitmap = (xfBitmap*) memblt->bitmap;
|
||||
xf_set_rop3(xfi, gdi_rop3_code(memblt->bRop));
|
||||
|
@ -665,19 +613,12 @@ void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XCopyArea(xfi->display, bitmap->pixmap, xfi->drawable, xfi->gc,
|
||||
memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight,
|
||||
memblt->nLeftRect, memblt->nTopRect);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight);
|
||||
}
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
||||
|
@ -690,7 +631,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
brush = &mem3blt->brush;
|
||||
bitmap = (xfBitmap*) mem3blt->bitmap;
|
||||
|
@ -738,13 +679,6 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
|||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XCopyArea(xfi->display, bitmap->pixmap, xfi->drawable, xfi->gc,
|
||||
mem3blt->nXSrc, mem3blt->nYSrc, mem3blt->nWidth, mem3blt->nHeight,
|
||||
mem3blt->nLeftRect, mem3blt->nTopRect);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight);
|
||||
}
|
||||
|
||||
|
@ -756,7 +690,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
|||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc)
|
||||
|
@ -766,7 +700,7 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc)
|
|||
UINT32 brush_color;
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_set_rop2(xfi, polygon_sc->bRop2);
|
||||
brush_color = freerdp_color_convert_var(polygon_sc->brushColor, ((xfContext*)context)->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
@ -813,7 +747,7 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc)
|
|||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
free(points);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
||||
|
@ -826,7 +760,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
|||
UINT32 backColor;
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
brush = &(polygon_cb->brush);
|
||||
xf_set_rop2(xfi, polygon_cb->bRop2);
|
||||
|
@ -920,7 +854,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
|||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
free(points);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_ellipse_sc(rdpContext* context, ELLIPSE_SC_ORDER* ellipse_sc)
|
||||
|
@ -941,7 +875,7 @@ void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surf
|
|||
xfi = ((xfContext*) context)->xfi;
|
||||
settings = xfi->instance->settings;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
switch (surface_frame_marker->frameAction)
|
||||
{
|
||||
|
@ -955,15 +889,8 @@ void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surf
|
|||
|
||||
case SURFACECMD_FRAMEACTION_END:
|
||||
xfi->frame_begin = FALSE;
|
||||
if (xfi->frame_x2 > xfi->frame_x1 && xfi->frame_y2 > xfi->frame_y1)
|
||||
if ((xfi->frame_x2 > xfi->frame_x1) && (xfi->frame_y2 > xfi->frame_y1))
|
||||
{
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
XSetFillStyle(xfi->display, xfi->gc, FillSolid);
|
||||
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
|
||||
xfi->frame_x1, xfi->frame_y1,
|
||||
xfi->frame_x2 - xfi->frame_x1, xfi->frame_y2 - xfi->frame_y1,
|
||||
xfi->frame_x1, xfi->frame_y1);
|
||||
gdi_InvalidateRegion(xfi->hdc, xfi->frame_x1, xfi->frame_y1,
|
||||
xfi->frame_x2 - xfi->frame_x1, xfi->frame_y2 - xfi->frame_y1);
|
||||
}
|
||||
|
@ -974,12 +901,12 @@ void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surf
|
|||
break;
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
static void xf_gdi_surface_update_frame(xfInfo* xfi, UINT16 tx, UINT16 ty, UINT16 width, UINT16 height)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
if (!xfi->remote_app)
|
||||
{
|
||||
if (xfi->frame_begin)
|
||||
{
|
||||
|
@ -1000,8 +927,6 @@ static void xf_gdi_surface_update_frame(xfInfo* xfi, UINT16 tx, UINT16 ty, UINT1
|
|||
}
|
||||
else
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
|
||||
tx, ty, width, height, tx, ty);
|
||||
gdi_InvalidateRegion(xfi->hdc, tx, ty, width, height);
|
||||
}
|
||||
}
|
||||
|
@ -1020,7 +945,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
|||
RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) xfi->rfx_context;
|
||||
NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) xfi->nsc_context;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX)
|
||||
{
|
||||
|
@ -1125,7 +1050,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
|||
printf("Unsupported codecID %d\n", surface_bits_command->codecID);
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_gdi_register_update_callbacks(rdpUpdate* update)
|
||||
|
|
|
@ -46,7 +46,7 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
|
|||
xfContext* context_ = (xfContext*) context;
|
||||
xfInfo* xfi = context_->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
pixmap = XCreatePixmap(xfi->display, xfi->drawable, bitmap->width, bitmap->height, xfi->depth);
|
||||
|
@ -78,19 +78,19 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
|
|||
|
||||
((xfBitmap*) bitmap)->pixmap = pixmap;
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
|
||||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (((xfBitmap*) bitmap)->pixmap != 0)
|
||||
XFreePixmap(xfi->display, ((xfBitmap*) bitmap)->pixmap);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
|
||||
|
@ -102,7 +102,7 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
|
|||
width = bitmap->right - bitmap->left + 1;
|
||||
height = bitmap->bottom - bitmap->top + 1;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
|
||||
|
@ -114,15 +114,9 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
|
|||
|
||||
XFree(image);
|
||||
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc,
|
||||
bitmap->left, bitmap->top, width, height, bitmap->left, bitmap->top);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, bitmap->left, bitmap->top, width, height);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
|
||||
|
@ -212,14 +206,14 @@ void xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
|
|||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (primary)
|
||||
xfi->drawing = xfi->primary;
|
||||
else
|
||||
xfi->drawing = ((xfBitmap*) bitmap)->pixmap;
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
/* Pointer Class */
|
||||
|
@ -230,7 +224,7 @@ void xf_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
|||
XcursorImage ci;
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
ZeroMemory(&ci, sizeof(ci));
|
||||
ci.version = XCURSOR_IMAGE_VERSION;
|
||||
|
@ -253,7 +247,7 @@ void xf_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
|||
|
||||
free(ci.pixels);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -262,12 +256,12 @@ void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
|||
#ifdef WITH_XCURSOR
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (((xfPointer*) pointer)->cursor != 0)
|
||||
XFreeCursor(xfi->display, ((xfPointer*) pointer)->cursor);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -276,14 +270,14 @@ void xf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
|
|||
#ifdef WITH_XCURSOR
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
/* in RemoteApp mode, window can be null if none has had focus */
|
||||
|
||||
if (xfi->window != NULL)
|
||||
XDefineCursor(xfi->display, xfi->window->handle, ((xfPointer*) pointer)->cursor);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -293,7 +287,7 @@ void xf_Pointer_SetNull(rdpContext* context)
|
|||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
static Cursor nullcursor = None;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (nullcursor == None)
|
||||
{
|
||||
|
@ -311,7 +305,7 @@ void xf_Pointer_SetNull(rdpContext* context)
|
|||
if (xfi->window != NULL && nullcursor != None)
|
||||
XDefineCursor(xfi->display, xfi->window->handle, nullcursor);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -320,12 +314,12 @@ void xf_Pointer_SetDefault(rdpContext* context)
|
|||
#ifdef WITH_XCURSOR
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (xfi->window != NULL)
|
||||
XUndefineCursor(xfi->display, xfi->window->handle);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -341,7 +335,7 @@ void xf_Glyph_New(rdpContext* context, rdpGlyph* glyph)
|
|||
xf_glyph = (xfGlyph*) glyph;
|
||||
xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
scanline = (glyph->cx + 7) / 8;
|
||||
|
||||
|
@ -357,19 +351,19 @@ void xf_Glyph_New(rdpContext* context, rdpGlyph* glyph)
|
|||
XPutImage(xfi->display, xf_glyph->pixmap, xfi->gc_mono, image, 0, 0, 0, 0, glyph->cx, glyph->cy);
|
||||
XFree(image);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
|
||||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (((xfGlyph*) glyph)->pixmap != 0)
|
||||
XFreePixmap(xfi->display, ((xfGlyph*) glyph)->pixmap);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Glyph_Draw(rdpContext* context, rdpGlyph* glyph, int x, int y)
|
||||
|
@ -379,14 +373,14 @@ void xf_Glyph_Draw(rdpContext* context, rdpGlyph* glyph, int x, int y)
|
|||
|
||||
xf_glyph = (xfGlyph*) glyph;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XSetStipple(xfi->display, xfi->gc, xf_glyph->pixmap);
|
||||
XSetTSOrigin(xfi->display, xfi->gc, x, y);
|
||||
XFillRectangle(xfi->display, xfi->drawing, xfi->gc, x, y, glyph->cx, glyph->cy);
|
||||
XSetStipple(xfi->display, xfi->gc, xfi->bitmap_mono);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height, UINT32 bgcolor, UINT32 fgcolor)
|
||||
|
@ -402,7 +396,7 @@ void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height
|
|||
freerdp_color_convert_var_bgr(fgcolor, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv):
|
||||
freerdp_color_convert_var_rgb(fgcolor, context_->settings->ColorDepth, xfi->bpp, xfi->clrconv);
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
XSetFillStyle(xfi->display, xfi->gc, FillSolid);
|
||||
|
@ -413,26 +407,21 @@ void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height
|
|||
XSetBackground(xfi->display, xfi->gc, fgcolor);
|
||||
XSetFillStyle(xfi->display, xfi->gc, FillStippled);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
void xf_Glyph_EndDraw(rdpContext* context, int x, int y, int width, int height, UINT32 bgcolor, UINT32 fgcolor)
|
||||
{
|
||||
xfInfo* xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (xfi->drawing == xfi->primary)
|
||||
{
|
||||
if (xfi->remote_app != TRUE)
|
||||
{
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, width, height, x, y);
|
||||
}
|
||||
|
||||
gdi_InvalidateRegion(xfi->hdc, x, y, width, height);
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
|
||||
/* Graphics Module */
|
||||
|
|
|
@ -41,11 +41,12 @@ void xf_kbd_init(xfInfo* xfi)
|
|||
xfi->keyboard_layout_id = xfi->instance->settings->KeyboardLayout;
|
||||
xfi->keyboard_layout_id = freerdp_keyboard_init(xfi->keyboard_layout_id);
|
||||
xfi->instance->settings->KeyboardLayout = xfi->keyboard_layout_id;
|
||||
xfi->modifier_map = XGetModifierMapping(xfi->display);
|
||||
}
|
||||
|
||||
void xf_kbd_clear(xfInfo* xfi)
|
||||
{
|
||||
memset(xfi->pressed_keys, 0, 256 * sizeof(BOOL));
|
||||
ZeroMemory(xfi->pressed_keys, 256 * sizeof(BOOL));
|
||||
}
|
||||
|
||||
void xf_kbd_set_keypress(xfInfo* xfi, BYTE keycode, KeySym keysym)
|
||||
|
@ -129,7 +130,7 @@ int xf_kbd_read_keyboard_state(xfInfo* xfi)
|
|||
Window wdummy;
|
||||
UINT32 state = 0;
|
||||
|
||||
if (xfi->remote_app != TRUE)
|
||||
if (!xfi->remote_app)
|
||||
{
|
||||
XQueryPointer(xfi->display, xfi->window->handle,
|
||||
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
|
||||
|
@ -154,6 +155,7 @@ BOOL xf_kbd_get_key_state(xfInfo* xfi, int state, int keysym)
|
|||
for (modifierpos = 0; modifierpos < 8; modifierpos++)
|
||||
{
|
||||
offset = xfi->modifier_map->max_keypermod * modifierpos;
|
||||
|
||||
for (key = 0; key < xfi->modifier_map->max_keypermod; key++)
|
||||
{
|
||||
if (xfi->modifier_map->modifiermap[offset + key] == keycode)
|
||||
|
@ -172,6 +174,7 @@ int xf_kbd_get_toggle_keys_state(xfInfo* xfi)
|
|||
int toggle_keys_state = 0;
|
||||
|
||||
state = xf_kbd_read_keyboard_state(xfi);
|
||||
|
||||
if (xf_kbd_get_key_state(xfi, state, XK_Scroll_Lock))
|
||||
toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
|
||||
if (xf_kbd_get_key_state(xfi, state, XK_Num_Lock))
|
||||
|
|
|
@ -112,6 +112,7 @@ void xf_SendClientEvent(xfInfo* xfi, xfWindow* window, Atom atom, unsigned int n
|
|||
}
|
||||
|
||||
DEBUG_X11("Send ClientMessage Event: wnd=0x%04X", (unsigned int) xevent.xclient.window);
|
||||
|
||||
XSendEvent(xfi->display, RootWindowOfScreen(xfi->screen), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
|
||||
XSync(xfi->display, False);
|
||||
|
@ -170,9 +171,8 @@ BOOL xf_GetCurrentDesktop(xfInfo* xfi)
|
|||
status = xf_GetWindowProperty(xfi, DefaultRootWindow(xfi->display),
|
||||
xfi->_NET_CURRENT_DESKTOP, 1, &nitems, &bytes, &prop);
|
||||
|
||||
if (status != TRUE) {
|
||||
if (status != TRUE)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xfi->current_desktop = (int) *prop;
|
||||
free(prop);
|
||||
|
@ -199,7 +199,8 @@ BOOL xf_GetWorkArea(xfInfo* xfi)
|
|||
if (status != TRUE)
|
||||
return FALSE;
|
||||
|
||||
if ((xfi->current_desktop * 4 + 3) >= nitems) {
|
||||
if ((xfi->current_desktop * 4 + 3) >= nitems)
|
||||
{
|
||||
free(prop);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -507,7 +508,7 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
|
|||
(UINT32) window->handle, window->left, window->top, window->right, window->bottom,
|
||||
window->width, window->height, wnd->windowId);
|
||||
|
||||
memset(&gcv, 0, sizeof(gcv));
|
||||
ZeroMemory(&gcv, sizeof(gcv));
|
||||
window->gc = XCreateGC(xfi->display, window->handle, GCGraphicsExposures, &gcv);
|
||||
|
||||
class_hints = XAllocClassHint();
|
||||
|
@ -939,12 +940,12 @@ rdpWindow* xf_rdpWindowFromWindow(xfInfo* xfi, Window wnd)
|
|||
if (xfi->_context != NULL)
|
||||
{
|
||||
rail = xfi->_context->rail;
|
||||
|
||||
if (rail != NULL)
|
||||
{
|
||||
return window_list_get_by_extra_id(rail->list, (void*)(long)wnd);
|
||||
}
|
||||
return window_list_get_by_extra_id(rail->list, (void*) (long) wnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -127,12 +127,12 @@ void xf_sw_end_paint(rdpContext* context)
|
|||
w = gdi->primary->hdc->hwnd->invalid->w;
|
||||
h = gdi->primary->hdc->hwnd->invalid->h;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h);
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ void xf_sw_end_paint(rdpContext* context)
|
|||
ninvalid = gdi->primary->hdc->hwnd->ninvalid;
|
||||
cinvalid = gdi->primary->hdc->hwnd->cinvalid;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
for (i = 0; i < ninvalid; i++)
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ void xf_sw_end_paint(rdpContext* context)
|
|||
|
||||
XFlush(xfi->display);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -174,11 +174,11 @@ void xf_sw_end_paint(rdpContext* context)
|
|||
w = gdi->primary->hdc->hwnd->invalid->w;
|
||||
h = gdi->primary->hdc->hwnd->invalid->h;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ void xf_sw_desktop_resize(rdpContext* context)
|
|||
xfi = ((xfContext*) context)->xfi;
|
||||
settings = xfi->instance->settings;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, TRUE);
|
||||
|
||||
if (xfi->fullscreen != TRUE)
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ void xf_sw_desktop_resize(rdpContext* context)
|
|||
}
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, TRUE);
|
||||
}
|
||||
|
||||
void xf_hw_begin_paint(rdpContext* context)
|
||||
|
@ -226,7 +226,54 @@ void xf_hw_end_paint(rdpContext* context)
|
|||
|
||||
xfi = ((xfContext*) context)->xfi;
|
||||
|
||||
if (xfi->remote_app)
|
||||
if (!xfi->remote_app)
|
||||
{
|
||||
if (!xfi->complex_regions)
|
||||
{
|
||||
if (xfi->hdc->hwnd->invalid->null)
|
||||
return;
|
||||
|
||||
x = xfi->hdc->hwnd->invalid->x;
|
||||
y = xfi->hdc->hwnd->invalid->y;
|
||||
w = xfi->hdc->hwnd->invalid->w;
|
||||
h = xfi->hdc->hwnd->invalid->h;
|
||||
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y);
|
||||
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
int ninvalid;
|
||||
HGDI_RGN cinvalid;
|
||||
|
||||
if (xfi->hdc->hwnd->ninvalid < 1)
|
||||
return;
|
||||
|
||||
ninvalid = xfi->hdc->hwnd->ninvalid;
|
||||
cinvalid = xfi->hdc->hwnd->cinvalid;
|
||||
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
for (i = 0; i < ninvalid; i++)
|
||||
{
|
||||
x = cinvalid[i].x;
|
||||
y = cinvalid[i].y;
|
||||
w = cinvalid[i].w;
|
||||
h = cinvalid[i].h;
|
||||
|
||||
XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y);
|
||||
}
|
||||
|
||||
XFlush(xfi->display);
|
||||
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xfi->hdc->hwnd->invalid->null)
|
||||
return;
|
||||
|
@ -236,11 +283,11 @@ void xf_hw_end_paint(rdpContext* context)
|
|||
w = xfi->hdc->hwnd->invalid->w;
|
||||
h = xfi->hdc->hwnd->invalid->h;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +300,7 @@ void xf_hw_desktop_resize(rdpContext* context)
|
|||
xfi = ((xfContext*) context)->xfi;
|
||||
settings = xfi->instance->settings;
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, TRUE);
|
||||
|
||||
if (xfi->fullscreen != TRUE)
|
||||
{
|
||||
|
@ -284,7 +331,7 @@ void xf_hw_desktop_resize(rdpContext* context)
|
|||
XFillRectangle(xfi->display, xfi->drawable, xfi->gc, 0, 0, xfi->width, xfi->height);
|
||||
}
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, TRUE);
|
||||
}
|
||||
|
||||
BOOL xf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
|
||||
|
@ -309,11 +356,11 @@ BOOL xf_process_x_events(freerdp* instance)
|
|||
|
||||
while (pending_status)
|
||||
{
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
pending_status = XPending(xfi->display);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
|
||||
if (pending_status)
|
||||
{
|
||||
|
@ -380,6 +427,8 @@ void xf_toggle_fullscreen(xfInfo* xfi)
|
|||
{
|
||||
Pixmap contents = 0;
|
||||
|
||||
xf_lock_x11(xfi, TRUE);
|
||||
|
||||
contents = XCreatePixmap(xfi->display, xfi->window->handle, xfi->width, xfi->height, xfi->depth);
|
||||
XCopyArea(xfi->display, xfi->primary, contents, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
|
||||
|
||||
|
@ -389,6 +438,34 @@ void xf_toggle_fullscreen(xfInfo* xfi)
|
|||
|
||||
XCopyArea(xfi->display, contents, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
|
||||
XFreePixmap(xfi->display, contents);
|
||||
|
||||
xf_unlock_x11(xfi, TRUE);
|
||||
}
|
||||
|
||||
void xf_lock_x11(xfInfo* xfi, BOOL display)
|
||||
{
|
||||
if (!xfi->UseXThreads)
|
||||
{
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (display)
|
||||
XLockDisplay(xfi->display);
|
||||
}
|
||||
}
|
||||
|
||||
void xf_unlock_x11(xfInfo* xfi, BOOL display)
|
||||
{
|
||||
if (!xfi->UseXThreads)
|
||||
{
|
||||
ReleaseMutex(xfi->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (display)
|
||||
XUnlockDisplay(xfi->display);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL xf_get_pixmap_info(xfInfo* xfi)
|
||||
|
@ -529,6 +606,8 @@ BOOL xf_pre_connect(freerdp* instance)
|
|||
|
||||
((xfContext*) instance->context)->xfi = xfi;
|
||||
|
||||
xfi->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
xfi->_context = instance->context;
|
||||
xfi->context = (xfContext*) instance->context;
|
||||
xfi->context->settings = instance->settings;
|
||||
|
@ -608,8 +687,16 @@ BOOL xf_pre_connect(freerdp* instance)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
if (!XInitThreads())
|
||||
printf("warning: XInitThreads() failure\n");
|
||||
xfi->UseXThreads = TRUE;
|
||||
|
||||
if (xfi->UseXThreads)
|
||||
{
|
||||
if (!XInitThreads())
|
||||
{
|
||||
printf("warning: XInitThreads() failure\n");
|
||||
xfi->UseXThreads = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
xfi->display = XOpenDisplay(NULL);
|
||||
|
||||
|
@ -1050,19 +1137,26 @@ void xf_free(xfInfo* xfi)
|
|||
|
||||
void* xf_update_thread(void* arg)
|
||||
{
|
||||
int status;
|
||||
wMessage message;
|
||||
wMessageQueue* queue;
|
||||
freerdp* instance = (freerdp*) arg;
|
||||
|
||||
status = 1;
|
||||
queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
|
||||
|
||||
while (MessageQueue_Wait(queue))
|
||||
{
|
||||
if (MessageQueue_Peek(queue, &message, TRUE))
|
||||
while (MessageQueue_Peek(queue, &message, TRUE))
|
||||
{
|
||||
if (!freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message))
|
||||
status = freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message);
|
||||
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!status)
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -1070,42 +1164,50 @@ void* xf_update_thread(void* arg)
|
|||
|
||||
void* xf_input_thread(void* arg)
|
||||
{
|
||||
int status;
|
||||
xfInfo* xfi;
|
||||
HANDLE event;
|
||||
XEvent xevent;
|
||||
wMessageQueue* queue;
|
||||
int pending_status = 1;
|
||||
int process_status = 1;
|
||||
freerdp* instance = (freerdp*) arg;
|
||||
|
||||
xfi = ((xfContext*) instance->context)->xfi;
|
||||
|
||||
event = CreateFileDescriptorEvent(NULL, TRUE, FALSE, xfi->xfds);
|
||||
event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfi->xfds);
|
||||
|
||||
while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
|
||||
status = XPending(xfi->display);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
|
||||
if (status)
|
||||
do
|
||||
{
|
||||
ZeroMemory(&xevent, sizeof(xevent));
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
WaitForSingleObject(xfi->mutex, INFINITE);
|
||||
pending_status = XPending(xfi->display);
|
||||
|
||||
XNextEvent(xfi->display, &xevent);
|
||||
status = xf_event_process(instance, &xevent);
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
|
||||
ReleaseMutex(xfi->mutex);
|
||||
if (pending_status)
|
||||
{
|
||||
xf_lock_x11(xfi, FALSE);
|
||||
|
||||
if (!status)
|
||||
break;
|
||||
ZeroMemory(&xevent, sizeof(xevent));
|
||||
XNextEvent(xfi->display, &xevent);
|
||||
process_status = xf_event_process(instance, &xevent);
|
||||
|
||||
xf_unlock_x11(xfi, FALSE);
|
||||
|
||||
if (!process_status)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (pending_status);
|
||||
|
||||
if (!process_status)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Closed from X\n");
|
||||
xfi->disconnect = TRUE;
|
||||
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
||||
MessageQueue_PostQuit(queue, 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1172,6 +1274,8 @@ int xfreerdp_run(freerdp* instance)
|
|||
|
||||
status = freerdp_connect(instance);
|
||||
|
||||
xfi = ((xfContext*) instance->context)->xfi;
|
||||
|
||||
/* Connection succeeded. --authonly ? */
|
||||
if (instance->settings->AuthenticationOnly)
|
||||
{
|
||||
|
@ -1182,19 +1286,16 @@ int xfreerdp_run(freerdp* instance)
|
|||
|
||||
if (!status)
|
||||
{
|
||||
xf_free(((xfContext*) instance->context)->xfi);
|
||||
xf_free(xfi);
|
||||
return XF_EXIT_CONN_FAILED;
|
||||
}
|
||||
|
||||
xfi = ((xfContext*) instance->context)->xfi;
|
||||
channels = instance->context->channels;
|
||||
settings = instance->context->settings;
|
||||
|
||||
async_update = settings->AsyncUpdate;
|
||||
async_input = settings->AsyncInput;
|
||||
|
||||
xfi->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
if (async_update)
|
||||
{
|
||||
update_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_update_thread, instance, 0, NULL);
|
||||
|
@ -1202,9 +1303,6 @@ int xfreerdp_run(freerdp* instance)
|
|||
|
||||
if (async_input)
|
||||
{
|
||||
input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
||||
fd_input_event = GetEventFileDescriptor(input_event);
|
||||
|
||||
input_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_input_thread, instance, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -1248,6 +1346,8 @@ int xfreerdp_run(freerdp* instance)
|
|||
}
|
||||
else
|
||||
{
|
||||
input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
||||
fd_input_event = GetEventFileDescriptor(input_event);
|
||||
rfds[rcount++] = (void*) (long) fd_input_event;
|
||||
}
|
||||
|
||||
|
@ -1271,11 +1371,11 @@ int xfreerdp_run(freerdp* instance)
|
|||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_status = select(max_fds + 1, &rfds_set, &wfds_set, NULL, &timeout);
|
||||
select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout);
|
||||
|
||||
if (select_status == 0)
|
||||
{
|
||||
continue;
|
||||
continue; /* select timeout */
|
||||
}
|
||||
else if (select_status == -1)
|
||||
{
|
||||
|
@ -1309,13 +1409,21 @@ int xfreerdp_run(freerdp* instance)
|
|||
{
|
||||
if (xf_process_x_events(instance) != TRUE)
|
||||
{
|
||||
printf("Closed from X\n");
|
||||
printf("Closed from X11\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
||||
if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (!freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE))
|
||||
{
|
||||
printf("User Disconnect\n");
|
||||
xfi->disconnect = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ struct xf_info
|
|||
HCLRCONV clrconv;
|
||||
Window parent_window;
|
||||
HANDLE mutex;
|
||||
BOOL UseXThreads;
|
||||
|
||||
HGDI_DC hdc;
|
||||
BOOL sw_gdi;
|
||||
|
@ -214,6 +215,9 @@ enum XF_EXIT_CODE
|
|||
XF_EXIT_UNKNOWN = 255,
|
||||
};
|
||||
|
||||
void xf_lock_x11(xfInfo* xfi, BOOL display);
|
||||
void xf_unlock_x11(xfInfo* xfi, BOOL display);
|
||||
|
||||
#ifdef WITH_DEBUG_X11
|
||||
#define DEBUG_X11(fmt, ...) DEBUG_CLASS(X11, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
|
|
|
@ -71,11 +71,21 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
|||
{ "compression", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, "z", "Compression" },
|
||||
{ "shell", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Alternate shell" },
|
||||
{ "shell-dir", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Shell working directory" },
|
||||
{ "sound", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "audio", "Audio output (sound)" },
|
||||
{ "microphone", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "mic", "Audio input (microphone)" },
|
||||
{ "audio-mode", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Audio output mode" },
|
||||
{ "mic", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Audio input (microphone)" },
|
||||
{ "multimedia", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "mmr", "Redirect multimedia (video)" },
|
||||
{ "network", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Network connection type" },
|
||||
{ "drive", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect drive" },
|
||||
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect all drives" },
|
||||
{ "home-drive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect home drive" },
|
||||
{ "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect clipboard" },
|
||||
{ "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Smooth fonts (cleartype)" },
|
||||
{ "serial", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
|
||||
{ "parallel", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect parallel device" },
|
||||
{ "smartcard", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect smartcard device" },
|
||||
{ "printer", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect printer device" },
|
||||
{ "usb", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect USB device" },
|
||||
{ "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Smooth fonts (ClearType)" },
|
||||
{ "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL, "Desktop composition" },
|
||||
{ "window-drag", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Full window drag" },
|
||||
{ "menu-anims", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Menu animations" },
|
||||
|
@ -85,7 +95,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
|||
{ "rfx", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "RemoteFX" },
|
||||
{ "rfx-mode", COMMAND_LINE_VALUE_REQUIRED, "<image|video>", NULL, NULL, -1, NULL, "RemoteFX mode" },
|
||||
{ "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Frame acknowledgement" },
|
||||
{ "nsc", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "NSCodec" },
|
||||
{ "nsc", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "nscodec", "NSCodec" },
|
||||
{ "jpeg", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "JPEG codec" },
|
||||
{ "jpeg-quality", COMMAND_LINE_VALUE_REQUIRED, "<percentage>", NULL, NULL, -1, NULL, "JPEG quality" },
|
||||
{ "nego", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "protocol security negotiation" },
|
||||
|
@ -159,7 +169,7 @@ int freerdp_client_print_command_line_help(int argc, char** argv)
|
|||
if (arg->Format)
|
||||
{
|
||||
length = strlen(arg->Name) + strlen(arg->Format) + 2;
|
||||
str = malloc(length + 1);
|
||||
str = (char*) malloc(length + 1);
|
||||
sprintf_s(str, length + 1, "%s:%s", arg->Name, arg->Format);
|
||||
printf("%-20s", str);
|
||||
free(str);
|
||||
|
@ -174,7 +184,7 @@ int freerdp_client_print_command_line_help(int argc, char** argv)
|
|||
else if (arg->Flags & COMMAND_LINE_VALUE_BOOL)
|
||||
{
|
||||
length = strlen(arg->Name) + 32;
|
||||
str = malloc(length + 1);
|
||||
str = (char*) malloc(length + 1);
|
||||
sprintf_s(str, length + 1, "%s (default:%s)", arg->Name,
|
||||
arg->Default ? "on" : "off");
|
||||
|
||||
|
@ -200,20 +210,20 @@ int freerdp_client_print_command_line_help(int argc, char** argv)
|
|||
printf("Clipboard Redirection: +clipboard\n");
|
||||
printf("\n");
|
||||
|
||||
printf("Drive Redirection: /a:drive,home,/home\n");
|
||||
printf("Smartcard Redirection: /a:smartcard,<device>\n");
|
||||
printf("Printer Redirection: /a:printer,<device>,<driver>\n");
|
||||
printf("Serial Port Redirection: /a:serial,<device>\n");
|
||||
printf("Parallel Port Redirection: /a:parallel,<device>\n");
|
||||
printf("Printer Redirection: /a:printer,<device>,<driver>\n");
|
||||
printf("Drive Redirection: /drive:home,/home/user\n");
|
||||
printf("Smartcard Redirection: /smartcard:<device>\n");
|
||||
printf("Printer Redirection: /printer:<device>,<driver>\n");
|
||||
printf("Serial Port Redirection: /serial:<device>\n");
|
||||
printf("Parallel Port Redirection: /parallel:<device>\n");
|
||||
printf("Printer Redirection: /printer:<device>,<driver>\n");
|
||||
printf("\n");
|
||||
|
||||
printf("Audio Input Redirection: /dvc:audin,sys:alsa\n");
|
||||
printf("Audio Output Redirection: /vc:rdpsnd,sys:alsa\n");
|
||||
printf("Audio Output Redirection: /sound:sys:alsa\n");
|
||||
printf("Audio Input Redirection: /microphone:sys:alsa\n");
|
||||
printf("\n");
|
||||
|
||||
printf("Multimedia Redirection: /dvc:tsmf,sys:alsa\n");
|
||||
printf("USB Device Redirection: /dvc:urbdrc,id,dev:054c:0268\n");
|
||||
printf("Multimedia Redirection: /multimedia:sys:alsa\n");
|
||||
printf("USB Device Redirection: /usb:id,dev:054c:0268\n");
|
||||
printf("\n");
|
||||
|
||||
printf("More documentation is coming, in the meantime consult source files\n");
|
||||
|
@ -422,9 +432,22 @@ char** freerdp_command_line_parse_comma_separated_values(char* list, int* count)
|
|||
return p;
|
||||
}
|
||||
|
||||
char** freerdp_command_line_parse_comma_separated_values_offset(char* list, int* count)
|
||||
{
|
||||
char** p;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values(list, count);
|
||||
|
||||
p = (char**) realloc(p, sizeof(char*) * (*count + 1));
|
||||
MoveMemory(&p[1], p, sizeof(char*) * *count);
|
||||
(*count)++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT_A* arg)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
rdpSettings* settings = (rdpSettings*) context;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
|
||||
|
@ -432,7 +455,6 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT
|
|||
{
|
||||
char** p;
|
||||
int count;
|
||||
settings = (rdpSettings*) context;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count);
|
||||
|
||||
|
@ -447,7 +469,6 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT
|
|||
{
|
||||
char** p;
|
||||
int count;
|
||||
settings = (rdpSettings*) context;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count);
|
||||
|
||||
|
@ -459,7 +480,6 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT
|
|||
{
|
||||
char** p;
|
||||
int count;
|
||||
settings = (rdpSettings*) context;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count);
|
||||
|
||||
|
@ -467,6 +487,153 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT
|
|||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "drive")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "drive";
|
||||
|
||||
freerdp_client_add_device_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "serial")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "serial";
|
||||
|
||||
freerdp_client_add_device_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "parallel")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "parallel";
|
||||
|
||||
freerdp_client_add_device_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "smartcard")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "smartcard";
|
||||
|
||||
freerdp_client_add_device_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "printer")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "printer";
|
||||
|
||||
freerdp_client_add_device_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "usb")
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "urbdrc";
|
||||
|
||||
freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "sound")
|
||||
{
|
||||
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "rdpsnd";
|
||||
|
||||
freerdp_client_add_static_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* p[1];
|
||||
int count;
|
||||
|
||||
count = 1;
|
||||
p[0] = "rdpsnd";
|
||||
|
||||
freerdp_client_add_static_channel(settings, count, p);
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "microphone")
|
||||
{
|
||||
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "audin";
|
||||
|
||||
freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* p[1];
|
||||
int count;
|
||||
|
||||
count = 1;
|
||||
p[0] = "audin";
|
||||
|
||||
freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "multimedia")
|
||||
{
|
||||
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
|
||||
{
|
||||
char** p;
|
||||
int count;
|
||||
|
||||
p = freerdp_command_line_parse_comma_separated_values_offset(arg->Value, &count);
|
||||
p[0] = "tsmf";
|
||||
|
||||
freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* p[1];
|
||||
int count;
|
||||
|
||||
count = 1;
|
||||
p[0] = "tsmf";
|
||||
|
||||
freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
}
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
|
||||
|
@ -1051,6 +1218,14 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
|
|||
{
|
||||
settings->CompressionEnabled = arg->Value ? TRUE : FALSE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "drives")
|
||||
{
|
||||
settings->RedirectDrives = arg->Value ? TRUE : FALSE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "home-drive")
|
||||
{
|
||||
settings->RedirectHomeDrive = arg->Value ? TRUE : FALSE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "clipboard")
|
||||
{
|
||||
settings->RedirectClipboard = arg->Value ? TRUE : FALSE;
|
||||
|
@ -1405,6 +1580,38 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
|
|||
settings->AudioPlayback = TRUE; /* Both rdpsnd and tsmf require this flag to be set */
|
||||
}
|
||||
|
||||
if (settings->RedirectDrives)
|
||||
{
|
||||
settings->DeviceRedirection = TRUE;
|
||||
|
||||
if (!freerdp_device_collection_find(settings, "drive"))
|
||||
{
|
||||
char* params[3];
|
||||
|
||||
params[0] = "drive";
|
||||
params[1] = "media";
|
||||
params[2] = "*";
|
||||
|
||||
freerdp_client_add_device_channel(settings, 3, (char**) params);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->RedirectHomeDrive)
|
||||
{
|
||||
settings->DeviceRedirection = TRUE;
|
||||
|
||||
if (!freerdp_device_collection_find(settings, "drive"))
|
||||
{
|
||||
char* params[3];
|
||||
|
||||
params[0] = "drive";
|
||||
params[1] = "home";
|
||||
params[2] = "%";
|
||||
|
||||
freerdp_client_add_device_channel(settings, 3, (char**) params);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->DeviceRedirection)
|
||||
{
|
||||
freerdp_client_load_static_channel_addin(channels, settings, "rdpdr", settings);
|
||||
|
|
|
@ -121,7 +121,7 @@ int freerdp_client_old_process_plugin(rdpSettings* settings, ADDIN_ARGV* args)
|
|||
if (strcmp(args->argv[0], "cliprdr") == 0)
|
||||
{
|
||||
settings->RedirectClipboard = TRUE;
|
||||
printf("--plugin cliprdr -> --enable-clipboard\n");
|
||||
printf("--plugin cliprdr -> +clipboard\n");
|
||||
}
|
||||
else if (strcmp(args->argv[0], "rdpdr") == 0)
|
||||
{
|
||||
|
@ -398,37 +398,37 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
CommandLineSwitchCase(arg, "0")
|
||||
{
|
||||
settings->ConsoleSession = TRUE;
|
||||
printf("-0 -> --admin\n");
|
||||
printf("-0 -> /admin\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "a")
|
||||
{
|
||||
settings->ColorDepth = atoi(arg->Value);
|
||||
printf("-a %s -> --bpp %s\n", arg->Value, arg->Value);
|
||||
printf("-a %s -> /bpp:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "c")
|
||||
{
|
||||
settings->ShellWorkingDirectory = _strdup(arg->Value);
|
||||
printf("-c %s -> --shell-dir %s\n", arg->Value, arg->Value);
|
||||
printf("-c %s -> /shell-dir:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "D")
|
||||
{
|
||||
settings->Decorations = FALSE;
|
||||
printf("-D -> --disable-decorations\n");
|
||||
printf("-D -> -decorations\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "T")
|
||||
{
|
||||
settings->WindowTitle = _strdup(arg->Value);
|
||||
printf("-T %s -> --title %s\n", arg->Value, arg->Value);
|
||||
printf("-T %s -> /title:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "d")
|
||||
{
|
||||
settings->Domain = _strdup(arg->Value);
|
||||
printf("-d %s -> -d %s\n", arg->Value, arg->Value);
|
||||
printf("-d %s -> /d:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "f")
|
||||
{
|
||||
settings->Fullscreen = TRUE;
|
||||
printf("-f -> -f\n");
|
||||
printf("-f -> /f\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "g")
|
||||
{
|
||||
|
@ -445,18 +445,18 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
|
||||
free(str);
|
||||
|
||||
printf("-g %s -> --size %s or -w %d -h %d\n", arg->Value, arg->Value,
|
||||
printf("-g %s -> /size:%s or /w:%d /h:%d\n", arg->Value, arg->Value,
|
||||
settings->DesktopWidth, settings->DesktopHeight);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "k")
|
||||
{
|
||||
sscanf(arg->Value, "%X", &(settings->KeyboardLayout));
|
||||
printf("-k %s -> --kbd %s\n", arg->Value, arg->Value);
|
||||
printf("-k %s -> /kbd:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "K")
|
||||
{
|
||||
settings->GrabKeyboard = FALSE;
|
||||
printf("-K -> --disable-grab-keyboard\n");
|
||||
printf("-K -> -grab-keyboard\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "n")
|
||||
{
|
||||
|
@ -465,27 +465,27 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
CommandLineSwitchCase(arg, "o")
|
||||
{
|
||||
settings->RemoteConsoleAudio = TRUE;
|
||||
printf("-o -> --audio-mode 1\n");
|
||||
printf("-o -> /audio-mode:1\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "p")
|
||||
{
|
||||
settings->Password = _strdup(arg->Value);
|
||||
printf("-p %s -> -p %s\n", arg->Value, arg->Value);
|
||||
printf("-p %s -> /p:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "s")
|
||||
{
|
||||
settings->AlternateShell = _strdup(arg->Value);
|
||||
printf("-s %s -> --shell %s\n", arg->Value, arg->Value);
|
||||
printf("-s %s -> /shell:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "t")
|
||||
{
|
||||
settings->ServerPort = atoi(arg->Value);
|
||||
printf("-t %s -> --port %s\n", arg->Value, arg->Value);
|
||||
printf("-t %s -> /port:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "u")
|
||||
{
|
||||
settings->Username = _strdup(arg->Value);
|
||||
printf("-u %s -> -u %s\n", arg->Value, arg->Value);
|
||||
printf("-u %s -> /u:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "x")
|
||||
{
|
||||
|
@ -512,7 +512,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
settings->PerformanceFlags = type;
|
||||
}
|
||||
|
||||
printf("-x %s -> --network ", arg->Value);
|
||||
printf("-x %s -> /network ", arg->Value);
|
||||
|
||||
if (type == CONNECTION_TYPE_MODEM)
|
||||
printf("modem");
|
||||
|
@ -526,17 +526,17 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
CommandLineSwitchCase(arg, "X")
|
||||
{
|
||||
settings->ParentWindowId = strtol(arg->Value, NULL, 0);
|
||||
printf("-X %s -> --parent-window %s\n", arg->Value, arg->Value);
|
||||
printf("-X %s -> /parent-window:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "z")
|
||||
{
|
||||
settings->CompressionEnabled = TRUE;
|
||||
printf("-z -> --compression\n");
|
||||
printf("-z -> /compression\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "app")
|
||||
{
|
||||
settings->RemoteApplicationMode = TRUE;
|
||||
printf("--app -> --app + program name or alias\n");
|
||||
printf("--app -> /app + program name or alias\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "ext")
|
||||
{
|
||||
|
@ -545,7 +545,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
CommandLineSwitchCase(arg, "no-auth")
|
||||
{
|
||||
settings->Authentication = FALSE;
|
||||
printf("--no-auth -> --disable-authentication\n");
|
||||
printf("--no-auth -> -authentication\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "authonly")
|
||||
{
|
||||
|
@ -559,12 +559,12 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
{
|
||||
settings->FastPathInput = FALSE;
|
||||
settings->FastPathOutput = FALSE;
|
||||
printf("--no-fastpath -> --disable-fast-path\n");
|
||||
printf("--no-fastpath -> -fast-path\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-motion")
|
||||
{
|
||||
settings->MouseMotion = FALSE;
|
||||
printf("--no-motion -> --disable-mouse-motion\n");
|
||||
printf("--no-motion -> -mouse-motion\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "gdi")
|
||||
{
|
||||
|
@ -573,26 +573,26 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
else if (strcmp(arg->Value, "hw") == 0)
|
||||
settings->SoftwareGdi = FALSE;
|
||||
|
||||
printf("--gdi %s -> --gdi %s\n", arg->Value, arg->Value);
|
||||
printf("--gdi %s -> /gdi:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-osb")
|
||||
{
|
||||
settings->OffscreenSupportLevel = FALSE;
|
||||
printf("--no-osb -> --disable-offscreen-cache\n");
|
||||
printf("--no-osb -> -offscreen-cache\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-bmp-cache")
|
||||
{
|
||||
settings->BitmapCacheEnabled = FALSE;
|
||||
printf("--no-bmp-cache -> --disable-bitmap-cache\n");
|
||||
printf("--no-bmp-cache -> -bitmap-cache\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "plugin")
|
||||
{
|
||||
printf("--plugin -> -a, --vc, --dvc and channel-specific options\n");
|
||||
printf("--plugin -> /a, /vc, /dvc and channel-specific options\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "rfx")
|
||||
{
|
||||
settings->RemoteFxCodec = TRUE;
|
||||
printf("--rfx -> --rfx\n");
|
||||
printf("--rfx -> /rfx\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "rfx-mode")
|
||||
{
|
||||
|
@ -600,37 +600,38 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
settings->RemoteFxCodecMode = 0x00;
|
||||
else if (arg->Value[0] == 'i')
|
||||
settings->RemoteFxCodecMode = 0x02;
|
||||
printf("--rfx-mode -> --rfx-mode\n");
|
||||
|
||||
printf("--rfx-mode -> /rfx-mode\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "nsc")
|
||||
{
|
||||
settings->NSCodec = TRUE;
|
||||
printf("--nsc -> --nsc\n");
|
||||
printf("--nsc -> /nsc\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "disable-wallpaper")
|
||||
{
|
||||
settings->DisableWallpaper = TRUE;
|
||||
printf("--disable-wallpaper -> --disable-wallpaper\n");
|
||||
printf("--disable-wallpaper -> -wallpaper\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "composition")
|
||||
{
|
||||
settings->AllowDesktopComposition = TRUE;
|
||||
printf("--composition -> --enable-composition\n");
|
||||
printf("--composition -> +composition\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "disable-full-window-drag")
|
||||
{
|
||||
settings->DisableFullWindowDrag = TRUE;
|
||||
printf("--disable-full-window-drag -> --disable-window-drag\n");
|
||||
printf("--disable-full-window-drag -> -window-drag\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "disable-menu-animations")
|
||||
{
|
||||
settings->DisableMenuAnims = TRUE;
|
||||
printf("--disable-menu-animations -> --disable-menu-anims\n");
|
||||
printf("--disable-menu-animations -> -menu-anims\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "disable-theming")
|
||||
{
|
||||
settings->DisableThemes = TRUE;
|
||||
printf("--disable-theming -> --disable-themes\n");
|
||||
printf("--disable-theming -> -themes\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "ntlm")
|
||||
{
|
||||
|
@ -639,7 +640,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
CommandLineSwitchCase(arg, "ignore-certificate")
|
||||
{
|
||||
settings->IgnoreCertificate = TRUE;
|
||||
printf("--ignore-certificate -> --cert-ignore\n");
|
||||
printf("--ignore-certificate -> /cert-ignore\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "sec")
|
||||
{
|
||||
|
@ -665,22 +666,22 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
settings->NlaSecurity = TRUE;
|
||||
}
|
||||
|
||||
printf("--sec %s -> --sec %s\n", arg->Value, arg->Value);
|
||||
printf("--sec %s -> /sec:%s\n", arg->Value, arg->Value);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-rdp")
|
||||
{
|
||||
settings->RdpSecurity = FALSE;
|
||||
printf("--no-rdp -> --disable-sec-rdp\n");
|
||||
printf("--no-rdp -> -sec-rdp\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-tls")
|
||||
{
|
||||
settings->TlsSecurity = FALSE;
|
||||
printf("--no-tls -> --disable-sec-tls\n");
|
||||
printf("--no-tls -> -sec-tls\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "no-nla")
|
||||
{
|
||||
settings->NlaSecurity = FALSE;
|
||||
printf("--no-nla -> --disable-sec-nla\n");
|
||||
printf("--no-nla -> -sec-nla\n");
|
||||
}
|
||||
CommandLineSwitchCase(arg, "secure-checksum")
|
||||
{
|
||||
|
@ -695,10 +696,10 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
|||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
|
||||
printf("%s -> -v %s", settings->ServerHostname, settings->ServerHostname);
|
||||
printf("%s -> /v:%s", settings->ServerHostname, settings->ServerHostname);
|
||||
|
||||
if (settings->ServerPort != 3389)
|
||||
printf(" --port %d", settings->ServerPort);
|
||||
printf(" /port:%d", settings->ServerPort);
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# XCode files
|
||||
DerivedData
|
||||
project.xcworkspace/
|
||||
xcuserdata/
|
||||
bin/
|
||||
build/
|
||||
project.pbxproj
|
||||
!iFreeRDP.xcodeproj/
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// OrderedDictionary.h
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Modified version (Added indexForKey/Value functions)
|
||||
//
|
||||
// Created by Matt Gallagher on 19/12/08.
|
||||
// Copyright 2008 Matt Gallagher. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OrderedDictionary : NSMutableDictionary
|
||||
{
|
||||
NSMutableDictionary *dictionary;
|
||||
NSMutableArray *array;
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex;
|
||||
- (id)keyAtIndex:(NSUInteger)anIndex;
|
||||
- (NSUInteger)indexForValue:(id)value;
|
||||
- (NSUInteger)indexForKey:(id)key;
|
||||
- (NSEnumerator *)reverseKeyEnumerator;
|
||||
|
||||
@end
|
|
@ -0,0 +1,168 @@
|
|||
//
|
||||
// OrderedDictionary.m
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Modified version (Added indexForKey/Value functions)
|
||||
//
|
||||
// Created by Matt Gallagher on 19/12/08.
|
||||
// Copyright 2008 Matt Gallagher. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import "OrderedDictionary.h"
|
||||
|
||||
NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent)
|
||||
{
|
||||
NSString *objectString;
|
||||
if ([object isKindOfClass:[NSString class]])
|
||||
{
|
||||
objectString = (NSString *)[[object retain] autorelease];
|
||||
}
|
||||
else if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)])
|
||||
{
|
||||
objectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent];
|
||||
}
|
||||
else if ([object respondsToSelector:@selector(descriptionWithLocale:)])
|
||||
{
|
||||
objectString = [(NSSet *)object descriptionWithLocale:locale];
|
||||
}
|
||||
else
|
||||
{
|
||||
objectString = [object description];
|
||||
}
|
||||
return objectString;
|
||||
}
|
||||
|
||||
@implementation OrderedDictionary
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithCapacity:0];
|
||||
}
|
||||
|
||||
- (id)initWithCapacity:(NSUInteger)capacity
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
|
||||
array = [[NSMutableArray alloc] initWithCapacity:capacity];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[dictionary release];
|
||||
[array release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [self mutableCopy];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)anObject forKey:(id)aKey
|
||||
{
|
||||
if (![dictionary objectForKey:aKey])
|
||||
{
|
||||
[array addObject:aKey];
|
||||
}
|
||||
[dictionary setObject:anObject forKey:aKey];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(id)aKey
|
||||
{
|
||||
[dictionary removeObjectForKey:aKey];
|
||||
[array removeObject:aKey];
|
||||
}
|
||||
|
||||
- (NSUInteger)count
|
||||
{
|
||||
return [dictionary count];
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id)aKey
|
||||
{
|
||||
return [dictionary objectForKey:aKey];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)keyEnumerator
|
||||
{
|
||||
return [array objectEnumerator];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)reverseKeyEnumerator
|
||||
{
|
||||
return [array reverseObjectEnumerator];
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex
|
||||
{
|
||||
if ([dictionary objectForKey:aKey])
|
||||
{
|
||||
[self removeObjectForKey:aKey];
|
||||
}
|
||||
[array insertObject:aKey atIndex:anIndex];
|
||||
[dictionary setObject:anObject forKey:aKey];
|
||||
}
|
||||
|
||||
- (id)keyAtIndex:(NSUInteger)anIndex
|
||||
{
|
||||
return [array objectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexForKey:(id)key
|
||||
{
|
||||
return [array indexOfObject:key];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexForValue:(id)value
|
||||
{
|
||||
NSArray* keys = [self allKeysForObject:value];
|
||||
if ([keys count] > 0)
|
||||
{
|
||||
return [self indexForKey:[keys objectAtIndex:0]];
|
||||
}
|
||||
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
|
||||
{
|
||||
NSMutableString *indentString = [NSMutableString string];
|
||||
NSUInteger i, count = level;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
[indentString appendFormat:@" "];
|
||||
}
|
||||
|
||||
NSMutableString *description = [NSMutableString string];
|
||||
[description appendFormat:@"%@{\n", indentString];
|
||||
for (NSObject *key in self)
|
||||
{
|
||||
[description appendFormat:@"%@ %@ = %@;\n",
|
||||
indentString,
|
||||
DescriptionForObject(key, locale, level),
|
||||
DescriptionForObject([self objectForKey:key], locale, level)];
|
||||
}
|
||||
[description appendFormat:@"%@}\n", indentString];
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Additions to Cocoa touch classes
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Dorian Johnson, Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSObject (TSXAdditions)
|
||||
- (void)setValuesForKeyPathsWithDictionary:(NSDictionary *)keyedValues;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@interface NSString (TSXAdditions)
|
||||
+ (NSString*)stringWithUUID;
|
||||
- (NSData*)dataFromHexString;
|
||||
+ (NSString*)hexStringFromData:(const unsigned char *)data ofSize:(unsigned int)size withSeparator:(NSString *)sep afterNthChar:(int)sepnth;
|
||||
@end
|
||||
|
||||
@interface NSDictionary (TSXAdditions)
|
||||
- (id)mutableDeepCopy;
|
||||
@end
|
||||
|
||||
@interface NSData (TSXAdditions)
|
||||
- (NSString *)hexadecimalString;
|
||||
- (NSString *)base64EncodedString;
|
||||
@end
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
Additions to Cocoa touch classes
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Dorian Johnson, Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "TSXAdditions.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
@implementation NSObject (TSXAdditions)
|
||||
|
||||
- (void)setValuesForKeyPathsWithDictionary:(NSDictionary *)keyedValues
|
||||
{
|
||||
for (id keyPath in keyedValues)
|
||||
[self setValue:[keyedValues objectForKey:keyPath] forKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
if([self respondsToSelector:@selector(mutableCopyWithZone:)])
|
||||
return [self mutableCopy];
|
||||
else if([self respondsToSelector:@selector(copyWithZone:)])
|
||||
return [self copy];
|
||||
else
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation NSString (TSXAdditions)
|
||||
|
||||
#pragma mark Creation routines
|
||||
+ (NSString*)stringWithUUID
|
||||
{
|
||||
CFUUIDRef uuidObj = CFUUIDCreate(nil);
|
||||
NSString* uuidString = (NSString*)CFUUIDCreateString(nil, uuidObj);
|
||||
CFRelease(uuidObj);
|
||||
return [uuidString autorelease];
|
||||
}
|
||||
|
||||
/* Code from http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMNSData%2BHex.m?r=344 */
|
||||
- (NSData*)dataFromHexString
|
||||
{
|
||||
NSData *hexData = [self dataUsingEncoding:NSASCIIStringEncoding];
|
||||
const char *hexBuf = [hexData bytes];
|
||||
NSUInteger hexLen = [hexData length];
|
||||
|
||||
// This indicates an error converting to ASCII.
|
||||
if (!hexData)
|
||||
return nil;
|
||||
|
||||
if ((hexLen % 2) != 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *binaryData = [NSMutableData dataWithLength:(hexLen / 2)];
|
||||
unsigned char *binaryPtr = [binaryData mutableBytes];
|
||||
unsigned char value = 0;
|
||||
for (NSUInteger i = 0; i < hexLen; i++) {
|
||||
char c = hexBuf[i];
|
||||
|
||||
if (!isxdigit(c)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (isdigit(c)) {
|
||||
value += c - '0';
|
||||
} else if (islower(c)) {
|
||||
value += 10 + c - 'a';
|
||||
} else {
|
||||
value += 10 + c - 'A';
|
||||
}
|
||||
|
||||
if (i & 1) {
|
||||
*binaryPtr++ = value;
|
||||
value = 0;
|
||||
} else {
|
||||
value <<= 4;
|
||||
}
|
||||
}
|
||||
|
||||
return [NSData dataWithData:binaryData];
|
||||
}
|
||||
|
||||
+ (NSString*)hexStringFromData:(const unsigned char *)data ofSize:(unsigned int)size withSeparator:(NSString *)sep afterNthChar:(int)sepnth
|
||||
{
|
||||
int i;
|
||||
NSMutableString *result;
|
||||
NSString *immutableResult;
|
||||
|
||||
result = [[NSMutableString alloc] init];
|
||||
for (i = 0; i < size; i++) {
|
||||
if(i && sep && sepnth && i%sepnth==0)
|
||||
[result appendString:sep];
|
||||
[result appendFormat:@"%02X", data[i]];
|
||||
}
|
||||
|
||||
immutableResult = [NSString stringWithString:result];
|
||||
[result release];
|
||||
return immutableResult;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark Mutable deep copy for dicionary, array and set
|
||||
|
||||
@implementation NSDictionary (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableDictionary *newDictionary = [[NSMutableDictionary alloc] init];
|
||||
NSEnumerator *enumerator = [self keyEnumerator];
|
||||
id key;
|
||||
while((key = [enumerator nextObject]))
|
||||
{
|
||||
id obj = [[self objectForKey:key] mutableDeepCopy];
|
||||
[newDictionary setObject:obj forKey:key];
|
||||
[obj release];
|
||||
}
|
||||
return newDictionary;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSArray (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableArray *newArray = [[NSMutableArray alloc] init];
|
||||
NSEnumerator *enumerator = [self objectEnumerator];
|
||||
id obj;
|
||||
while((obj = [enumerator nextObject]))
|
||||
{
|
||||
obj = [obj mutableDeepCopy];
|
||||
[newArray addObject:obj];
|
||||
[obj release];
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSet (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableSet *newSet = [[NSMutableSet alloc] init];
|
||||
NSEnumerator *enumerator = [self objectEnumerator];
|
||||
id obj;
|
||||
while((obj = [enumerator nextObject]))
|
||||
{
|
||||
obj = [obj mutableDeepCopy];
|
||||
[newSet addObject:obj];
|
||||
[obj release];
|
||||
}
|
||||
return newSet;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/* Code from http://stackoverflow.com/questions/1305225/best-way-to-serialize-a-nsdata-into-an-hexadeximal-string */
|
||||
@implementation NSData (TSXAdditions)
|
||||
|
||||
#pragma mark - String Conversion
|
||||
- (NSString *)hexadecimalString {
|
||||
/* Returns hexadecimal string of NSData. Empty string if data is empty. */
|
||||
|
||||
const unsigned char *dataBuffer = (const unsigned char *)[self bytes];
|
||||
|
||||
if (!dataBuffer)
|
||||
return [NSString string];
|
||||
|
||||
NSUInteger dataLength = [self length];
|
||||
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
|
||||
|
||||
for (int i = 0; i < dataLength; ++i)
|
||||
[hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
|
||||
|
||||
return [NSString stringWithString:hexString];
|
||||
}
|
||||
|
||||
/* Code from http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html */
|
||||
- (NSString *)base64EncodedString
|
||||
{
|
||||
// Construct an OpenSSL context
|
||||
BIO *context = BIO_new(BIO_s_mem());
|
||||
|
||||
// Tell the context to encode base64
|
||||
BIO *command = BIO_new(BIO_f_base64());
|
||||
context = BIO_push(command, context);
|
||||
BIO_set_flags(context, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// Encode all the data
|
||||
BIO_write(context, [self bytes], [self length]);
|
||||
(void)BIO_flush(context);
|
||||
|
||||
// Get the data out of the context
|
||||
char *outputBuffer;
|
||||
long outputLength = BIO_get_mem_data(context, &outputBuffer);
|
||||
NSString *encodedString = [[NSString alloc] initWithBytes:outputBuffer length:outputLength encoding:NSASCIIStringEncoding];
|
||||
|
||||
BIO_free_all(context);
|
||||
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/***************************************************************************
|
||||
|
||||
Toast+UIView.h
|
||||
Toast
|
||||
Version 0.1
|
||||
|
||||
Copyright (c) 2011 Charles Scalesse.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface UIView (Toast)
|
||||
|
||||
#define ToastDurationLong 5.0
|
||||
#define ToastDurationNormal 3.0
|
||||
#define ToastDurationShort 1.0
|
||||
|
||||
// each makeToast method creates a view and displays it as toast
|
||||
-(void)makeToast:(NSString *)message;
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point;
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point title:(NSString *)title;
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point title:(NSString *)title image:(UIImage *)image;
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point image:(UIImage *)image;
|
||||
|
||||
// the showToast method displays an existing view as toast
|
||||
-(void)showToast:(UIView *)toast;
|
||||
-(void)showToast:(UIView *)toast duration:(float)interval position:(id)point;
|
||||
|
||||
@end
|
|
@ -0,0 +1,307 @@
|
|||
/***************************************************************************
|
||||
|
||||
Toast+UIView.h
|
||||
Toast
|
||||
Version 0.1
|
||||
|
||||
Copyright (c) 2011 Charles Scalesse.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#import "Toast+UIView.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define kMaxWidth 0.8
|
||||
#define kMaxHeight 0.8
|
||||
|
||||
#define kHorizontalPadding 10.0
|
||||
#define kVerticalPadding 10.0
|
||||
#define kCornerRadius 10.0
|
||||
#define kOpacity 0.8
|
||||
#define kFontSize 16.0
|
||||
#define kMaxTitleLines 999
|
||||
#define kMaxMessageLines 999
|
||||
|
||||
#define kFadeDuration 0.2
|
||||
|
||||
#define kDefaultLength 3
|
||||
#define kDefaultPosition @"bottom"
|
||||
|
||||
#define kImageWidth 80.0
|
||||
#define kImageHeight 80.0
|
||||
|
||||
static NSString *kDurationKey = @"duration";
|
||||
|
||||
|
||||
@interface UIView (ToastPrivate)
|
||||
|
||||
-(CGPoint)getPositionFor:(id)position toast:(UIView *)toast;
|
||||
-(UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIView (Toast)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Toast Methods
|
||||
|
||||
-(void)makeToast:(NSString *)message {
|
||||
[self makeToast:message duration:kDefaultLength position:kDefaultPosition];
|
||||
}
|
||||
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point {
|
||||
UIView *toast = [self makeViewForMessage:message title:nil image:nil];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point title:(NSString *)title {
|
||||
UIView *toast = [self makeViewForMessage:message title:title image:nil];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point image:(UIImage *)image {
|
||||
UIView *toast = [self makeViewForMessage:message title:nil image:image];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point title:(NSString *)title image:(UIImage *)image {
|
||||
UIView *toast = [self makeViewForMessage:message title:title image:image];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
-(void)showToast:(UIView *)toast {
|
||||
[self showToast:toast duration:kDefaultLength position:kDefaultPosition];
|
||||
}
|
||||
|
||||
-(void)showToast:(UIView *)toast duration:(float)interval position:(id)point {
|
||||
|
||||
/****************************************************
|
||||
* *
|
||||
* Displays a view for a given duration & position. *
|
||||
* *
|
||||
****************************************************/
|
||||
|
||||
CGPoint toastPoint = [self getPositionFor:point toast:toast];
|
||||
|
||||
//use an associative reference to associate the toast view with the display interval
|
||||
objc_setAssociatedObject (toast, &kDurationKey, [NSNumber numberWithFloat:interval], OBJC_ASSOCIATION_RETAIN);
|
||||
|
||||
[toast setCenter:toastPoint];
|
||||
[toast setAlpha:0.0];
|
||||
[self addSubview:toast];
|
||||
|
||||
[UIView beginAnimations:@"fade_in" context:toast];
|
||||
[UIView setAnimationDuration:kFadeDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
|
||||
[toast setAlpha:1.0];
|
||||
[UIView commitAnimations];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Animation Delegate Method
|
||||
|
||||
- (void)animationDidStop:(NSString*)animationID finished:(BOOL)finished context:(void *)context {
|
||||
|
||||
UIView *toast = (UIView *)context;
|
||||
|
||||
// retrieve the display interval associated with the view
|
||||
float interval = [(NSNumber *)objc_getAssociatedObject(toast, &kDurationKey) floatValue];
|
||||
|
||||
if([animationID isEqualToString:@"fade_in"]) {
|
||||
|
||||
[UIView beginAnimations:@"fade_out" context:toast];
|
||||
[UIView setAnimationDelay:interval];
|
||||
[UIView setAnimationDuration:kFadeDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
|
||||
[toast setAlpha:0.0];
|
||||
[UIView commitAnimations];
|
||||
|
||||
} else if ([animationID isEqualToString:@"fade_out"]) {
|
||||
|
||||
[toast removeFromSuperview];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Private Methods
|
||||
|
||||
-(CGPoint)getPositionFor:(id)point toast:(UIView *)toast {
|
||||
|
||||
/*************************************************************************************
|
||||
* *
|
||||
* Converts string literals @"top", @"bottom", @"center", or any point wrapped in an *
|
||||
* NSValue object into a CGPoint *
|
||||
* *
|
||||
*************************************************************************************/
|
||||
|
||||
if([point isKindOfClass:[NSString class]]) {
|
||||
|
||||
if( [point caseInsensitiveCompare:@"top"] == NSOrderedSame ) {
|
||||
return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + kVerticalPadding);
|
||||
} else if( [point caseInsensitiveCompare:@"bottom"] == NSOrderedSame ) {
|
||||
return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - kVerticalPadding);
|
||||
} else if( [point caseInsensitiveCompare:@"center"] == NSOrderedSame ) {
|
||||
return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
|
||||
}
|
||||
|
||||
} else if ([point isKindOfClass:[NSValue class]]) {
|
||||
return [point CGPointValue];
|
||||
}
|
||||
|
||||
NSLog(@"Error: Invalid position for toast.");
|
||||
return [self getPositionFor:kDefaultPosition toast:toast];
|
||||
}
|
||||
|
||||
-(UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image {
|
||||
|
||||
/***********************************************************************************
|
||||
* *
|
||||
* Dynamically build a toast view with any combination of message, title, & image. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
|
||||
if((message == nil) && (title == nil) && (image == nil)) return nil;
|
||||
|
||||
UILabel *messageLabel = nil;
|
||||
UILabel *titleLabel = nil;
|
||||
UIImageView *imageView = nil;
|
||||
|
||||
// create the parent view
|
||||
UIView *wrapperView = [[[UIView alloc] init] autorelease];
|
||||
[wrapperView.layer setCornerRadius:kCornerRadius];
|
||||
[wrapperView setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:kOpacity]];
|
||||
wrapperView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
|
||||
if(image != nil) {
|
||||
imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
|
||||
[imageView setContentMode:UIViewContentModeScaleAspectFit];
|
||||
[imageView setFrame:CGRectMake(kHorizontalPadding, kVerticalPadding, kImageWidth, kImageHeight)];
|
||||
}
|
||||
|
||||
float imageWidth, imageHeight, imageLeft;
|
||||
|
||||
// the imageView frame values will be used to size & position the other views
|
||||
if(imageView != nil) {
|
||||
imageWidth = imageView.bounds.size.width;
|
||||
imageHeight = imageView.bounds.size.height;
|
||||
imageLeft = kHorizontalPadding;
|
||||
} else {
|
||||
imageWidth = imageHeight = imageLeft = 0;
|
||||
}
|
||||
|
||||
if (title != nil) {
|
||||
titleLabel = [[[UILabel alloc] init] autorelease];
|
||||
[titleLabel setNumberOfLines:kMaxTitleLines];
|
||||
[titleLabel setFont:[UIFont boldSystemFontOfSize:kFontSize]];
|
||||
[titleLabel setTextAlignment:UITextAlignmentLeft];
|
||||
[titleLabel setLineBreakMode:UILineBreakModeWordWrap];
|
||||
[titleLabel setTextColor:[UIColor whiteColor]];
|
||||
[titleLabel setBackgroundColor:[UIColor clearColor]];
|
||||
[titleLabel setAlpha:1.0];
|
||||
[titleLabel setText:title];
|
||||
|
||||
// size the title label according to the length of the text
|
||||
CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth, self.bounds.size.height * kMaxHeight);
|
||||
CGSize expectedSizeTitle = [title sizeWithFont:titleLabel.font constrainedToSize:maxSizeTitle lineBreakMode:titleLabel.lineBreakMode];
|
||||
[titleLabel setFrame:CGRectMake(0, 0, expectedSizeTitle.width, expectedSizeTitle.height)];
|
||||
}
|
||||
|
||||
if (message != nil) {
|
||||
messageLabel = [[[UILabel alloc] init] autorelease];
|
||||
[messageLabel setNumberOfLines:kMaxMessageLines];
|
||||
[messageLabel setFont:[UIFont systemFontOfSize:kFontSize]];
|
||||
[messageLabel setLineBreakMode:UILineBreakModeWordWrap];
|
||||
[messageLabel setTextColor:[UIColor whiteColor]];
|
||||
[messageLabel setTextAlignment:UITextAlignmentCenter];
|
||||
[messageLabel setBackgroundColor:[UIColor clearColor]];
|
||||
[messageLabel setAlpha:1.0];
|
||||
[messageLabel setText:message];
|
||||
|
||||
// size the message label according to the length of the text
|
||||
CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth, self.bounds.size.height * kMaxHeight);
|
||||
CGSize expectedSizeMessage = [message sizeWithFont:messageLabel.font constrainedToSize:maxSizeMessage lineBreakMode:messageLabel.lineBreakMode];
|
||||
[messageLabel setFrame:CGRectMake(0, 0, expectedSizeMessage.width, expectedSizeMessage.height)];
|
||||
}
|
||||
|
||||
// titleLabel frame values
|
||||
float titleWidth, titleHeight, titleTop, titleLeft;
|
||||
|
||||
if(titleLabel != nil) {
|
||||
titleWidth = titleLabel.bounds.size.width;
|
||||
titleHeight = titleLabel.bounds.size.height;
|
||||
titleTop = kVerticalPadding;
|
||||
titleLeft = imageLeft + imageWidth + kHorizontalPadding;
|
||||
} else {
|
||||
titleWidth = titleHeight = titleTop = titleLeft = 0;
|
||||
}
|
||||
|
||||
// messageLabel frame values
|
||||
float messageWidth, messageHeight, messageLeft, messageTop;
|
||||
|
||||
if(messageLabel != nil) {
|
||||
messageWidth = messageLabel.bounds.size.width;
|
||||
messageHeight = messageLabel.bounds.size.height;
|
||||
messageLeft = imageLeft + imageWidth + kHorizontalPadding;
|
||||
messageTop = titleTop + titleHeight + kVerticalPadding;
|
||||
} else {
|
||||
messageWidth = messageHeight = messageLeft = messageTop = 0;
|
||||
}
|
||||
|
||||
// compare the title & message widths and use the longer value to calculate the size of the wrapper width
|
||||
// the same logic applies to the x value (left)
|
||||
float longerWidth = (messageWidth < titleWidth) ? titleWidth : messageWidth;
|
||||
float longerLeft = (messageLeft < titleLeft) ? titleLeft : messageLeft;
|
||||
|
||||
// if the image width is larger than longerWidth, use the image width to calculate the wrapper width.
|
||||
// the same logic applies to the wrapper height
|
||||
float wrapperWidth = ((longerLeft + longerWidth + kHorizontalPadding) < imageWidth + (kHorizontalPadding * 2)) ? imageWidth + (kHorizontalPadding * 2) : (longerLeft + longerWidth + kHorizontalPadding);
|
||||
float wrapperHeight = ((messageTop + messageHeight + kVerticalPadding) < imageHeight + (kVerticalPadding * 2)) ? imageHeight + (kVerticalPadding * 2) : (messageTop + messageHeight + kVerticalPadding);
|
||||
|
||||
[wrapperView setFrame:CGRectMake(0, 0, wrapperWidth, wrapperHeight)];
|
||||
|
||||
if(titleLabel != nil) {
|
||||
[titleLabel setFrame:CGRectMake(titleLeft, titleTop, titleWidth, titleHeight)];
|
||||
[wrapperView addSubview:titleLabel];
|
||||
}
|
||||
|
||||
if(messageLabel != nil) {
|
||||
[messageLabel setFrame:CGRectMake(messageLeft, messageTop, messageWidth, messageHeight)];
|
||||
[wrapperView addSubview:messageLabel];
|
||||
}
|
||||
|
||||
if(imageView != nil) {
|
||||
[wrapperView addSubview:imageView];
|
||||
}
|
||||
|
||||
return wrapperView;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
App delegate
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class MainTabBarController;
|
||||
|
||||
@interface AppDelegate : NSObject <UIApplicationDelegate> {
|
||||
|
||||
MainTabBarController* _tabBarController;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UIWindow *window;
|
||||
@property (nonatomic, retain) IBOutlet MainTabBarController* tabBarController;
|
||||
|
||||
@end
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
App delegate
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "AboutController.h"
|
||||
#import "HelpController.h"
|
||||
#import "BookmarkListController.h"
|
||||
#import "AppSettingsController.h"
|
||||
#import "MainTabBarController.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
||||
@synthesize window = _window, tabBarController = _tabBarController;
|
||||
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
// Set default values for most NSUserDefaults
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Defaults" ofType:@"plist"]]];
|
||||
|
||||
// init global settings
|
||||
SetSwapMouseButtonsFlag([[NSUserDefaults standardUserDefaults] boolForKey:@"ui.swap_mouse_buttons"]);
|
||||
SetInvertScrollingFlag([[NSUserDefaults standardUserDefaults] boolForKey:@"ui.invert_scrolling"]);
|
||||
|
||||
// create bookmark view and navigation controller
|
||||
BookmarkListController* bookmarkListController = [[[BookmarkListController alloc] initWithNibName:@"BookmarkListView" bundle:nil] autorelease];
|
||||
UINavigationController* bookmarkNavigationController = [[[UINavigationController alloc] initWithRootViewController:bookmarkListController] autorelease];
|
||||
|
||||
// create app settings view and navigation controller
|
||||
AppSettingsController* appSettingsController = [[[AppSettingsController alloc] initWithStyle:UITableViewStyleGrouped] autorelease];
|
||||
UINavigationController* appSettingsNavigationController = [[[UINavigationController alloc] initWithRootViewController:appSettingsController] autorelease];
|
||||
|
||||
// create help view controller
|
||||
HelpController* helpViewController = [[[HelpController alloc] initWithNibName:nil bundle:nil] autorelease];
|
||||
|
||||
// create about view controller
|
||||
AboutController* aboutViewController = [[[AboutController alloc] initWithNibName:nil bundle:nil] autorelease];
|
||||
|
||||
// add tab-bar controller to the main window and display everything
|
||||
NSArray* tabItems = [NSArray arrayWithObjects:bookmarkNavigationController, appSettingsNavigationController, helpViewController, aboutViewController, nil];
|
||||
[_tabBarController setViewControllers:tabItems];
|
||||
if ([_window respondsToSelector:@selector(setRootViewController:)])
|
||||
[_window setRootViewController:_tabBarController];
|
||||
else
|
||||
[_window addSubview:[_tabBarController view]];
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
/*
|
||||
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
/*
|
||||
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
/*
|
||||
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
*/
|
||||
// cancel disconnect timer
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
/*
|
||||
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
/*
|
||||
Called when the application is about to terminate.
|
||||
Save data if appropriate.
|
||||
See also applicationDidEnterBackground:.
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_window release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,54 @@
|
|||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# Android Client
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2013 Martin Fleisz <mfleisz@thinstuff.at>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(IOS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(IOS_PACKAGE_NAME "iFreeRDP")
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/iFreeRDP.xcodeproj/project.pbxproj.cmake ${CMAKE_CURRENT_SOURCE_DIR}/iFreeRDP.xcodeproj/project.pbxproj @ONLY)
|
||||
|
||||
if(IOS_BUILD_OBJC)
|
||||
# And isn't shiped with the android ndk/sdk so
|
||||
# we need to find it on the local machine
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER, BOTH)
|
||||
find_program(XCODEBUILD_COMMAND xcodebuild)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER, ONLY)
|
||||
|
||||
if(XCODEBUILD_COMMAND STREQUAL "XCODEBUILD_COMMAND-NOTFOUND")
|
||||
message(FATAL_ERROR "xcodebuild not found but required to build ios objective-c")
|
||||
endif()
|
||||
|
||||
if(IOS_BUILD_OBJC_DEBUG)
|
||||
set(IOS_BUILD_TYPE "Debug")
|
||||
else()
|
||||
set(IOS_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
set(IOS_APP_OUTPUT_DIR "${IOS_SOURCE_DIR}/bin/${IOS_BUILD_TYPE}")
|
||||
set(IOS_APP "${IOS_APP_OUTPUT_DIR}/${IOS_PACKAGE_NAME}.app")
|
||||
|
||||
# command to create the ios package
|
||||
add_custom_command(
|
||||
OUTPUT "${IOS_APP}"
|
||||
COMMAND ${XCODEBUILD_COMMAND} -project "${IOS_SOURCE_DIR}/iFreeRDP.xcodeproj" -sdk ${CMAKE_IOS_SDK_ROOT} -configuration ${IOS_BUILD_TYPE} CONFIGURATION_BUILD_DIR="${IOS_APP_OUTPUT_DIR}"
|
||||
WORKING_DIRECTORY "${IOS_SOURCE_DIR}"
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/iFreeRDP.xcodeproj/project.pbxproj
|
||||
DEPENDS freerdp winpr
|
||||
)
|
||||
add_custom_target(ios-package ALL SOURCES "${IOS_APP}")
|
||||
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "bin;build")
|
||||
endif()
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Application info controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface AboutController : UIViewController <UIWebViewDelegate, UIAlertViewDelegate>
|
||||
{
|
||||
NSString* last_link_clicked;
|
||||
UIWebView* webView;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Application info controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "AboutController.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation AboutController
|
||||
|
||||
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
|
||||
|
||||
// set title and tab-bar image
|
||||
[self setTitle:NSLocalizedString(@"About", @"About Controller title")];
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_about" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"About", @"Tabbar item about") image:tabBarIcon tag:0]];
|
||||
|
||||
last_link_clicked = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[last_link_clicked release];
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
|
||||
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
|
||||
[webView setAutoresizesSubviews:YES];
|
||||
[webView setDelegate:self];
|
||||
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
|
||||
[self setView:webView];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString *filename = (IsPhone() ? @"about_phone" : @"about");
|
||||
NSString *htmlString = [[[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:@"html" inDirectory:@"about_page"] encoding:NSUTF8StringEncoding error:nil] autorelease];
|
||||
|
||||
[webView loadHTMLString:[NSString stringWithFormat:htmlString,
|
||||
TSXAppFullVersion(),
|
||||
[[UIDevice currentDevice] systemName],
|
||||
[[UIDevice currentDevice] systemVersion],
|
||||
[[UIDevice currentDevice] model]] baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"about_page"]]];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIWebView callbacks
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
if([[request URL] isFileURL])
|
||||
return YES;
|
||||
|
||||
if(navigationType == UIWebViewNavigationTypeLinkClicked)
|
||||
{
|
||||
[last_link_clicked release];
|
||||
last_link_clicked = [[[request URL] absoluteString] retain];
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"External Link", @"External Link Alert Title")
|
||||
message:[NSString stringWithFormat:NSLocalizedString(@"Open [%@] in Browser?", @"Open link in browser (with link as parameter)"), last_link_clicked]
|
||||
delegate:self
|
||||
cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button")
|
||||
otherButtonTitles:NSLocalizedString(@"No", @"No Button"), nil];
|
||||
[alert show];
|
||||
[alert release];
|
||||
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark UIAlertView delegate
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
if (buttonIndex == 0)
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:last_link_clicked]];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Controller to edit advanced bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface AdvancedBookmarkEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
}
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
Controller to edit advanced bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "AdvancedBookmarkEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
#import "EditorSelectionController.h"
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "PerformanceEditorController.h"
|
||||
|
||||
@interface AdvancedBookmarkEditorController ()
|
||||
|
||||
@end
|
||||
|
||||
#define SECTION_ADVANCED_SETTINGS 0
|
||||
#define SECTION_COUNT 1
|
||||
|
||||
@implementation AdvancedBookmarkEditorController
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:NSLocalizedString(@"Advanced Settings", @"Advanced Settings title")];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// we need to reload the table view data here to have up-to-date data for the
|
||||
// advanced settings accessory items (like for resolution/color mode settings)
|
||||
[[self tableView] reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS: // advanced settings
|
||||
return 7;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS:
|
||||
return NSLocalizedString(@"Advanced", @"'Advanced': advanced settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS: // advanced settings
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0: // 3G Settings
|
||||
cellType = TableCellIdentifierYesNo;
|
||||
break;
|
||||
case 1: // 3G screen/color depth
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 2: // 3G performance settings
|
||||
cellType = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
case 3: // security mode
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 4: // remote program
|
||||
case 5: // work dir
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
case 6: // console mode
|
||||
cellType = TableCellIdentifierYesNo;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// advanced settings
|
||||
case SECTION_ADVANCED_SETTINGS:
|
||||
[self initAdvancedSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// updates advanced settings in the UI
|
||||
- (void)initAdvancedSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
BOOL enable_3G_settings = [_params boolForKey:@"enable_3g_settings"];
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"3G Settings", @"'3G Settings': Bookmark enable 3G settings")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[_params boolForKey:@"enable_3g_settings"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"3G Screen", @"'3G Screen': Bookmark 3G Screen settings")];
|
||||
NSString* resolution = ScreenResolutionDescription([_params intForKeyPath:@"settings_3g.screen_resolution_type"], [_params intForKeyPath:@"settings_3g.width"], [_params intForKeyPath:@"settings_3g.height"]);
|
||||
int colorBits = [_params intForKeyPath:@"settings_3g.colors"];
|
||||
[[selCell selection] setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
|
||||
[[selCell label] setEnabled:enable_3G_settings];
|
||||
[[selCell selection] setEnabled:enable_3G_settings];
|
||||
[selCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"3G Performance", @"'3G Performance': Bookmark 3G Performance Settings")];
|
||||
[[editCell label] setEnabled:enable_3G_settings];
|
||||
[editCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone];
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"Security", @"'Security': Bookmark protocl security settings")];
|
||||
[[selCell selection] setText:ProtocolSecurityDescription([_params intForKey:@"security"])];
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Remote Program", @"'Remote Program': Bookmark remote program settings")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"remote_program"]];
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Working Directory", @"'Working Directory': Bookmark working directory settings")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"working_dir"]];
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Console Mode", @"'Console Mode': Bookmark console mode settings")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[_params boolForKey:@"console"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIViewController* viewCtrl = nil;
|
||||
|
||||
// determine view
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 1:
|
||||
if ([_params boolForKey:@"enable_3g_settings"])
|
||||
viewCtrl = [[[ScreenSelectionController alloc] initWithConnectionParams:_params keyPath:@"settings_3g"] autorelease];
|
||||
break;
|
||||
case 2:
|
||||
if ([_params boolForKey:@"enable_3g_settings"])
|
||||
viewCtrl = [[[PerformanceEditorController alloc] initWithConnectionParams:_params keyPath:@"settings_3g"] autorelease];
|
||||
break;
|
||||
case 3:
|
||||
viewCtrl = [[[EditorSelectionController alloc] initWithConnectionParams:_params entries:[NSArray arrayWithObject:@"security"] selections:[NSArray arrayWithObject:SelectionForSecuritySetting()]] autorelease];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// display view
|
||||
if(viewCtrl)
|
||||
[[self navigationController] pushViewController:viewCtrl animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update remote program/work dir settings
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 4):
|
||||
{
|
||||
[_params setValue:[textField text] forKey:@"remote_program"];
|
||||
break;
|
||||
}
|
||||
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 5):
|
||||
{
|
||||
[_params setValue:[textField text] forKey:@"working_dir"];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (void)toggleSettingValue:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch(valueSwitch.tag)
|
||||
{
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 0):
|
||||
[_params setBool:[valueSwitch isOn] forKey:@"enable_3g_settings"];
|
||||
NSArray* indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:SECTION_ADVANCED_SETTINGS], [NSIndexPath indexPathForRow:2 inSection:SECTION_ADVANCED_SETTINGS], nil];
|
||||
[[self tableView] reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 6):
|
||||
[_params setBool:[valueSwitch isOn] forKey:@"console"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
Controller to specify application wide settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@interface AppSettingsController : EditorBaseController
|
||||
|
||||
@end
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
Controller to specify application wide settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "AppSettingsController.h"
|
||||
#import "Utils.h"
|
||||
#import "Toast+UIView.h"
|
||||
|
||||
@implementation AppSettingsController
|
||||
|
||||
// keep this up-to-date for correct section display/hidding
|
||||
#define SECTION_UI_SETTINGS 0
|
||||
#define SECTION_CERTIFICATE_HANDLING_SETTINGS 1
|
||||
#define SECTION_NUM_SECTIONS 2
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
|
||||
- (id)initWithStyle:(UITableViewStyle)style
|
||||
{
|
||||
if ((self = [super initWithStyle:style]))
|
||||
{
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_settings" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Settings", @"Tabbar item settings") image:tabBarIcon tag:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View lifecycle
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// set title
|
||||
[self setTitle:NSLocalizedString(@"Settings", @"App Settings title")];
|
||||
}
|
||||
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_NUM_SECTIONS;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_UI_SETTINGS: // UI settings
|
||||
return 5;
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS: // certificate handling settings
|
||||
return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
return NSLocalizedString(@"User Interface", @"UI settings section title");
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
return NSLocalizedString(@"Server Certificate Handling", @"Server Certificate Handling section title");
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellIdentifier = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
cellIdentifier = TableCellIdentifierYesNo;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
cellIdentifier = TableCellIdentifierYesNo;
|
||||
break;
|
||||
case 1:
|
||||
cellIdentifier = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSAssert(cellIdentifier != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellIdentifier];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
[self initUISettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
[self initCertificateHandlingSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Initialization helpers
|
||||
|
||||
// updates UI settings in the UI
|
||||
- (void)initUISettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Hide Status Bar", "Show/Hide Phone Status Bar setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_status_bar"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Hide Tool Bar", "Show/Hide Tool Bar setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Swap Mouse Buttons", "Swap Mouse Button UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.swap_mouse_buttons"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Invert Scrolling", "Invert Scrolling UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.invert_scrolling"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Touch Pointer Auto Scroll", "Touch Pointer Auto Scroll UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.auto_scroll_touchpointer"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// updates certificate handling settings in the UI
|
||||
- (void)initCertificateHandlingSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Accept all Certificates", "Accept All Certificates setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSubEditTableViewCell* subCell = (EditSubEditTableViewCell*)cell;
|
||||
[[subCell label] setText:NSLocalizedString(@"Erase Certificate Cache", @"Erase certificate cache button")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// deselect any row to fake a button-pressed like effect
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
// ensure everything is stored in our settings before we proceed
|
||||
[[self view] endEditing:NO];
|
||||
|
||||
// clear certificate cache
|
||||
if([indexPath section] == SECTION_CERTIFICATE_HANDLING_SETTINGS && [indexPath row] == 1)
|
||||
{
|
||||
// delete certificates cache
|
||||
NSError* err;
|
||||
if ([[NSFileManager defaultManager] removeItemAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"/.freerdp"] error:&err])
|
||||
[[self view] makeToast:NSLocalizedString(@"Certificate Cache cleared!", @"Clear Certificate cache success message") duration:ToastDurationNormal position:@"center"];
|
||||
else
|
||||
[[self view] makeToast:NSLocalizedString(@"Error clearing the Certificate Cache!", @"Clear Certificate cache failed message") duration:ToastDurationNormal position:@"center"];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)toggleSettingValue:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch([valueSwitch tag])
|
||||
{
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 0):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.hide_status_bar"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 1):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.hide_tool_bar"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 2):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.swap_mouse_buttons"];
|
||||
SetSwapMouseButtonsFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 3):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.invert_scrolling"];
|
||||
SetInvertScrollingFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 4):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.auto_scroll_touchpointer"];
|
||||
SetInvertScrollingFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CERTIFICATE_HANDLING_SETTINGS, 0):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"security.accept_certificates"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Bookmark editor controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
|
||||
@protocol BookmarkEditorDelegate <NSObject>
|
||||
// bookmark editing finsihed
|
||||
- (void)commitBookmark:(ComputerBookmark*)bookmark;
|
||||
@end
|
||||
|
||||
|
||||
@interface BookmarkEditorController : EditorBaseController <UIAlertViewDelegate>
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
|
||||
BOOL _display_server_settings;
|
||||
|
||||
id<BookmarkEditorDelegate> delegate;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) id<BookmarkEditorDelegate> delegate;
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
Bookmark editor controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "PerformanceEditorController.h"
|
||||
#import "CredentialsEditorController.h"
|
||||
#import "AdvancedBookmarkEditorController.h"
|
||||
|
||||
@implementation BookmarkEditorController
|
||||
|
||||
@synthesize delegate;
|
||||
|
||||
#define SECTION_SERVER 0
|
||||
#define SECTION_CREDENTIALS 1
|
||||
#define SECTION_SETTINGS 2
|
||||
#define SECTION_COUNT 3
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
|
||||
// if this is a TSX Connect bookmark - disable server settings
|
||||
if([_bookmark isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")])
|
||||
_display_server_settings = NO;
|
||||
else
|
||||
_display_server_settings = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View lifecycle
|
||||
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// replace back button with a custom handler that checks if the required bookmark settings were specified
|
||||
UIBarButtonItem* saveButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Save", @"Save Button title") style:UIBarButtonItemStyleDone target:self action:@selector(handleSave:)] autorelease];
|
||||
UIBarButtonItem* cancelButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Cancel", @"Cancel Button title") style:UIBarButtonItemStyleBordered target:self action:@selector(handleCancel:)] autorelease];
|
||||
[[self navigationItem] setLeftBarButtonItem:cancelButton];
|
||||
[[self navigationItem] setRightBarButtonItem:saveButton];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// we need to reload the table view data here to have up-to-date data for the
|
||||
// advanced settings accessory items (like for resolution/color mode settings)
|
||||
[[self tableView] reloadData];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_SERVER: // server settings
|
||||
return (_display_server_settings ? 3 : 0);
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
return 1;
|
||||
case SECTION_SETTINGS: // session settings
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_SERVER:
|
||||
return (_display_server_settings ? NSLocalizedString(@"Host", @"'Host': host settings header") : nil);
|
||||
case SECTION_CREDENTIALS:
|
||||
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
|
||||
case SECTION_SETTINGS:
|
||||
return NSLocalizedString(@"Settings", @"'Session Settings': session settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_SERVER:
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
|
||||
case SECTION_CREDENTIALS:
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
|
||||
case SECTION_SETTINGS: // settings
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0: // screen/color depth
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 1: // performance settings
|
||||
case 2: // advanced settings
|
||||
cellType = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// server settings
|
||||
case SECTION_SERVER:
|
||||
[self initServerSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
// credentials
|
||||
case SECTION_CREDENTIALS:
|
||||
[self initCredentialSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
// session settings
|
||||
case SECTION_SETTINGS:
|
||||
[self initSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// updates server settings in the UI
|
||||
- (void)initServerSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
[[textCell label] setText:NSLocalizedString(@"Label", @"'Label': Bookmark label")];
|
||||
[[textCell textfield] setText:[_bookmark label]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
case 1:
|
||||
[[textCell label] setText:NSLocalizedString(@"Host", @"'Host': Bookmark hostname")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"hostname"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
case 2:
|
||||
[[textCell label] setText:NSLocalizedString(@"Port", @"'Port': Bookmark port")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", [_params intForKey:@"port"]]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
}
|
||||
|
||||
// updates credentials in the UI
|
||||
- (void)initCredentialSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
[[selCell label] setText:NSLocalizedString(@"Credentials", @"'Credentials': Bookmark credentials")];
|
||||
[[selCell selection] setText:[_params StringForKey:@"username"]];
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// updates session settings in the UI
|
||||
- (void)initSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"Screen", @"'Screen': Bookmark Screen settings")];
|
||||
NSString* resolution = ScreenResolutionDescription([_params intForKey:@"screen_resolution_type"], [_params intForKey:@"width"], [_params intForKey:@"height"]);
|
||||
int colorBits = [_params intForKey:@"colors"];
|
||||
[[selCell selection] setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"Performance", @"'Performance': Bookmark Performance Settings")];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"Advanced", @"'Advanced': Bookmark Advanced Settings")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIViewController* viewCtrl = nil;
|
||||
|
||||
// determine view
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_CREDENTIALS:
|
||||
{
|
||||
if ([indexPath row] == 0)
|
||||
viewCtrl = [[[CredentialsEditorController alloc] initWithBookmark:_bookmark] autorelease];
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_SETTINGS:
|
||||
{
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
viewCtrl = [[[ScreenSelectionController alloc] initWithConnectionParams:_params] autorelease];
|
||||
break;
|
||||
case 1:
|
||||
viewCtrl = [[[PerformanceEditorController alloc] initWithConnectionParams:_params] autorelease];
|
||||
break;
|
||||
case 2:
|
||||
viewCtrl = [[[AdvancedBookmarkEditorController alloc] initWithBookmark:_bookmark] autorelease];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// display view
|
||||
if(viewCtrl)
|
||||
[[self navigationController] pushViewController:viewCtrl animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update server settings
|
||||
case GET_TAG(SECTION_SERVER, 0):
|
||||
[_bookmark setLabel:[textField text]];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_SERVER, 1):
|
||||
[_params setValue:[textField text] forKey:@"hostname"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_SERVER, 2):
|
||||
[_params setInt:[[textField text] intValue] forKey:@"port"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - UIAlertViewDelegate methods
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
// clicked yes?
|
||||
if (buttonIndex == 0)
|
||||
{
|
||||
// cancel bookmark editing and return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)handleSave:(id)sender
|
||||
{
|
||||
// resign any first responder (so that we finish editing any bookmark parameter that might be currently edited)
|
||||
[[self view] endEditing:NO];
|
||||
|
||||
// verify that bookmark is complete (only for manual bookmarks)
|
||||
if (![_bookmark isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")])
|
||||
{
|
||||
if ([[_bookmark label] length] == 0 || [[_params StringForKey:@"hostname"] length] == 0 || [_params intForKey:@"port"] == 0)
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cancel without saving?", @"Incomplete bookmark error title") message:NSLocalizedString(@"Press 'Cancel' to abort!\nPress 'Continue' to specify the required fields!", @"Incomplete bookmark error message") delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", @"Cancel Button") otherButtonTitles:NSLocalizedString(@"Continue", @"Continue Button"), nil] autorelease];
|
||||
[alertView show];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// commit bookmark
|
||||
if ([[self delegate] respondsToSelector:@selector(commitBookmark:)])
|
||||
[[self delegate] commitBookmark:_bookmark];
|
||||
|
||||
// return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)handleCancel:(id)sender
|
||||
{
|
||||
// return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory management
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Relinquish ownership any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
[_bookmark autorelease];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
bookmarks and active session view controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "Bookmark.h"
|
||||
#import "BookmarkTableCell.h"
|
||||
#import "SessionTableCell.h"
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "Reachability.h"
|
||||
|
||||
@interface BookmarkListController : UIViewController <UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, UIAlertViewDelegate, BookmarkEditorDelegate>
|
||||
{
|
||||
// custom bookmark and session table cells
|
||||
BookmarkTableCell* _bmTableCell;
|
||||
SessionTableCell* _sessTableCell;
|
||||
|
||||
// child views
|
||||
UISearchBar* _searchBar;
|
||||
UITableView* _tableView;
|
||||
|
||||
// array with search results (or nil if no search active)
|
||||
NSMutableArray* _manual_search_result;
|
||||
NSMutableArray* _tsxconnect_search_result;
|
||||
NSMutableArray* _history_search_result;
|
||||
|
||||
// bookmark arrays
|
||||
NSMutableArray* _manual_bookmarks;
|
||||
NSMutableArray* _tsxconnect_bookmarks;
|
||||
|
||||
// bookmark star images
|
||||
UIImage* _star_on_img;
|
||||
UIImage* _star_off_img;
|
||||
|
||||
// array with active sessions
|
||||
NSMutableArray* _active_sessions;
|
||||
|
||||
// array with connection history entries
|
||||
NSMutableArray* _connection_history;
|
||||
|
||||
// temporary bookmark when asking if the user wants to store a bookmark for a session initiated by a quick connect
|
||||
ComputerBookmark* _temporary_bookmark;
|
||||
|
||||
// reachability notification helper for tsx connect
|
||||
Reachability* _tsxconnect_reachability;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UISearchBar* searchBar;
|
||||
@property (nonatomic, retain) IBOutlet UITableView* tableView;
|
||||
@property (nonatomic, retain) IBOutlet BookmarkTableCell* bmTableCell;
|
||||
@property (nonatomic, retain) IBOutlet SessionTableCell* sessTableCell;
|
||||
|
||||
|
||||
@end
|
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
bookmarks and active session view controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "BookmarkListController.h"
|
||||
#import "Utils.h"
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "RDPSessionViewController.h"
|
||||
#import "Toast+UIView.h"
|
||||
#import "Reachability.h"
|
||||
|
||||
#define SECTION_SESSIONS 0
|
||||
#define SECTION_BOOKMARKS 1
|
||||
#define NUM_SECTIONS 2
|
||||
|
||||
@interface BookmarkListController (Private)
|
||||
#pragma mark misc functions
|
||||
- (UIButton*)disclosureButtonWithImage:(UIImage*)image;
|
||||
- (void)performSearch:(NSString*)searchText;
|
||||
#pragma mark Persisting bookmarks
|
||||
- (void)scheduleWriteBookmarksToDataStore;
|
||||
- (void)writeBookmarksToDataStore;
|
||||
- (void)scheduleWriteManualBookmarksToDataStore;
|
||||
- (void)writeManualBookmarksToDataStore;
|
||||
- (void)readManualBookmarksFromDataStore;
|
||||
- (void)writeArray:(NSArray*)bookmarks toDataStoreURL:(NSURL*)url;
|
||||
- (NSMutableArray*)arrayFromDataStoreURL:(NSURL*)url;
|
||||
- (NSURL*)manualBookmarksDataStoreURL;
|
||||
- (NSURL*)connectionHistoryDataStoreURL;
|
||||
@end
|
||||
|
||||
|
||||
@implementation BookmarkListController
|
||||
|
||||
@synthesize searchBar = _searchBar, tableView = _tableView, bmTableCell = _bmTableCell, sessTableCell = _sessTableCell;
|
||||
|
||||
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
|
||||
{
|
||||
// load bookmarks
|
||||
[self readManualBookmarksFromDataStore];
|
||||
|
||||
// load connection history
|
||||
[self readConnectionHistoryFromDataStore];
|
||||
|
||||
// init search result array
|
||||
_manual_search_result = nil;
|
||||
|
||||
// register for session notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionDisconnected:) name:TSXSessionDidDisconnectNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionFailedToConnect:) name:TSXSessionDidFailToConnectNotification object:nil];
|
||||
|
||||
// set title and tabbar controller image
|
||||
[self setTitle:NSLocalizedString(@"Connections", @"'Connections': bookmark controller title")];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemBookmarks tag:0]];
|
||||
|
||||
// load images
|
||||
_star_on_img = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon_accessory_star_on" ofType:@"png"]] retain];
|
||||
_star_off_img = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon_accessory_star_off" ofType:@"png"]] retain];
|
||||
|
||||
// init reachability detection
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
|
||||
|
||||
// init other properties
|
||||
_active_sessions = [[NSMutableArray alloc] init];
|
||||
_temporary_bookmark = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
}
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// set edit button to allow bookmark list editing
|
||||
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
|
||||
|
||||
/*
|
||||
if (![[InAppPurchaseManager sharedInAppPurchaseManager] isProVersion])
|
||||
[[self navigationItem] setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Go Pro" style:UIBarButtonItemStyleDone target:self action:@selector(goProButtonPressed:)]];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// in case we had a search - search again cause the bookmark searchable items could have changed
|
||||
if ([[_searchBar text] length] > 0)
|
||||
[self performSearch:[_searchBar text]];
|
||||
|
||||
// to reflect any bookmark changes - reload table
|
||||
[_tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// clear any search
|
||||
[_searchBar setText:@""];
|
||||
[_searchBar resignFirstResponder];
|
||||
[self performSearch:@""];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload {
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_tsxconnect_reachability stopNotifier];
|
||||
[_tsxconnect_reachability release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[_temporary_bookmark release];
|
||||
[_connection_history release];
|
||||
[_active_sessions release];
|
||||
[_tsxconnect_search_result release];
|
||||
[_manual_search_result release];
|
||||
[_manual_bookmarks release];
|
||||
[_tsxconnect_bookmarks release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return NUM_SECTIONS;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_SESSIONS:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
// (+1 for Add Bookmark entry)
|
||||
if(_manual_search_result != nil)
|
||||
return ([_manual_search_result count] + [_history_search_result count] + 1);
|
||||
return ([_manual_bookmarks count] + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UITableViewCell*)cellForGenericListEntry
|
||||
{
|
||||
static NSString *CellIdentifier = @"BookmarkListCell";
|
||||
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
[cell setAccessoryView:[self disclosureButtonWithImage:_star_off_img]];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (BookmarkTableCell*)cellForBookmark
|
||||
{
|
||||
static NSString *BookmarkCellIdentifier = @"BookmarkCell";
|
||||
BookmarkTableCell *cell = (BookmarkTableCell*)[[self tableView] dequeueReusableCellWithIdentifier:BookmarkCellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"BookmarkTableViewCell" owner:self options:nil];
|
||||
[_bmTableCell setAccessoryView:[self disclosureButtonWithImage:_star_on_img]];
|
||||
cell = _bmTableCell;
|
||||
_bmTableCell = nil;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
|
||||
switch ([indexPath section])
|
||||
{
|
||||
case SECTION_SESSIONS:
|
||||
{
|
||||
// get custom session cell
|
||||
static NSString *SessionCellIdentifier = @"SessionCell";
|
||||
SessionTableCell *cell = (SessionTableCell*)[tableView dequeueReusableCellWithIdentifier:SessionCellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"SessionTableViewCell" owner:self options:nil];
|
||||
cell = _sessTableCell;
|
||||
_sessTableCell = nil;
|
||||
}
|
||||
|
||||
// set cell data
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[indexPath row]];
|
||||
[[cell title] setText:[session sessionName]];
|
||||
[[cell server] setText:[[session params] StringForKey:@"hostname"]];
|
||||
if([[[cell server] text] length] == 0)
|
||||
[[cell server] setText:@"TSX Connect"];
|
||||
[[cell username] setText:[[session params] StringForKey:@"username"]];
|
||||
[[cell screenshot] setImage:[session getScreenshotWithSize:[[cell screenshot] bounds].size]];
|
||||
[[cell disconnectButton] setTag:[indexPath row]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
// special handling for first cell - quick connect/quick create Bookmark cell
|
||||
if([indexPath row] == 0)
|
||||
{
|
||||
// if a search text is entered the cell becomes a quick connect/quick create bookmark cell - otherwise it's just an add bookmark cell
|
||||
UITableViewCell* cell = [self cellForGenericListEntry];
|
||||
if ([[_searchBar text] length] == 0)
|
||||
{
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:NSLocalizedString(@"Add Connection", @"'Add Connection': button label")]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:[_searchBar text]]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:NO];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// do we have a history cell or bookmark cell?
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
UITableViewCell* cell = [self cellForGenericListEntry];
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:[_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]]]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:NO];
|
||||
return cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set cell properties
|
||||
ComputerBookmark* entry;
|
||||
BookmarkTableCell* cell = [self cellForBookmark];
|
||||
if(_manual_search_result == nil)
|
||||
entry = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
else
|
||||
entry = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
|
||||
[[cell title] setText:[entry label]];
|
||||
[[cell subTitle] setText:[[entry params] StringForKey:@"hostname"]];
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
NSAssert(0, @"Failed to create cell");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Override to support conditional editing of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// dont allow to edit Add Bookmark item
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
return NO;
|
||||
if([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Override to support editing the table view.
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if(editingStyle == UITableViewCellEditingStyleDelete)
|
||||
{
|
||||
// Delete the row from the data source
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
if (_manual_search_result == nil)
|
||||
[_manual_bookmarks removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
else
|
||||
{
|
||||
// history item or bookmark?
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
[_connection_history removeObject:[_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]]];
|
||||
[_history_search_result removeObjectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_manual_bookmarks removeObject:[[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"]];
|
||||
[_manual_search_result removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
}
|
||||
}
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Override to support rearranging the table view.
|
||||
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
|
||||
{
|
||||
if([fromIndexPath compare:toIndexPath] != NSOrderedSame)
|
||||
{
|
||||
switch([fromIndexPath section])
|
||||
{
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
int fromIdx = [self bookmarkIndexFromIndexPath:fromIndexPath];
|
||||
int toIdx = [self bookmarkIndexFromIndexPath:toIndexPath];
|
||||
ComputerBookmark* temp_bookmark = [[_manual_bookmarks objectAtIndex:fromIdx] retain];
|
||||
[_manual_bookmarks removeObjectAtIndex:fromIdx];
|
||||
if (toIdx >= [_manual_bookmarks count])
|
||||
[_manual_bookmarks addObject:temp_bookmark];
|
||||
else
|
||||
[_manual_bookmarks insertObject:temp_bookmark atIndex:toIdx];
|
||||
[temp_bookmark release];
|
||||
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// prevent that an item is moved befoer the Add Bookmark item
|
||||
-(NSIndexPath*)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
|
||||
{
|
||||
// don't allow to move:
|
||||
// - items between sections
|
||||
// - the quick connect/quick create bookmark cell
|
||||
// - any item while a search is applied
|
||||
if([proposedDestinationIndexPath row] == 0 || ([sourceIndexPath section] != [proposedDestinationIndexPath section]) ||
|
||||
_manual_search_result != nil || _tsxconnect_search_result != nil)
|
||||
{
|
||||
return sourceIndexPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return proposedDestinationIndexPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Override to support conditional rearranging of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// dont allow to reorder Add Bookmark item
|
||||
if([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if(section == SECTION_SESSIONS && [_active_sessions count] > 0)
|
||||
return NSLocalizedString(@"My Sessions", @"'My Session': section sessions header");
|
||||
if(section == SECTION_BOOKMARKS)
|
||||
return NSLocalizedString(@"Manual Connections", @"'Manual Connections': section manual bookmarks header");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)tableView:(UITableView*)tableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
return 72;
|
||||
return [tableView rowHeight];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
|
||||
{
|
||||
[super setEditing:editing animated:animated];
|
||||
[[self tableView] setEditing:editing animated:animated];
|
||||
}
|
||||
|
||||
- (void)accessoryButtonTapped:(UIControl*)button withEvent:(UIEvent*)event
|
||||
{
|
||||
// forward a tap on our custom accessory button to the real accessory button handler
|
||||
NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:[[[event touchesForView:button] anyObject] locationInView:[self tableView]]];
|
||||
if (indexPath == nil)
|
||||
return;
|
||||
|
||||
[[[self tableView] delegate] tableView:[self tableView] accessoryButtonTappedForRowWithIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
{
|
||||
// resume session
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[indexPath row]];
|
||||
UIViewController* ctrl = [[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView" bundle:nil session:session];
|
||||
[ctrl setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:ctrl animated:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
ComputerBookmark* bookmark = nil;
|
||||
if([indexPath section] == SECTION_BOOKMARKS)
|
||||
{
|
||||
// first row has either quick connect or add bookmark item
|
||||
if([indexPath row] == 0)
|
||||
{
|
||||
if ([[_searchBar text] length] == 0)
|
||||
{
|
||||
// show add bookmark controller
|
||||
BookmarkEditorController* bookmarkEditorController = [[[BookmarkEditorController alloc] initWithBookmark:[[ComputerBookmark alloc] initWithBaseDefaultParameters]] autorelease];
|
||||
[bookmarkEditorController setTitle:NSLocalizedString(@"Add Connection", @"Add Connection title")];
|
||||
[bookmarkEditorController setDelegate:self];
|
||||
[bookmarkEditorController setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:bookmarkEditorController animated:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a quick connect bookmark and add an entry to the quick connect history (if not already in the history)
|
||||
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
|
||||
if (![_connection_history containsObject:[_searchBar text]])
|
||||
{
|
||||
[_connection_history addObject:[_searchBar text]];
|
||||
[self scheduleWriteConnectionHistoryToDataStore];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_manual_search_result != nil)
|
||||
{
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
// create a quick connect bookmark for a history item
|
||||
NSString* item = [_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
bookmark = [self bookmarkForQuickConnectTo:item];
|
||||
}
|
||||
else
|
||||
bookmark = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
}
|
||||
else
|
||||
bookmark = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]; // -1 because of ADD BOOKMARK entry
|
||||
}
|
||||
|
||||
// set reachability status
|
||||
WakeUpWWAN();
|
||||
[bookmark setConntectedViaWLAN:[[Reachability reachabilityWithHostName:[[bookmark params] StringForKey:@"hostname"]] currentReachabilityStatus] == ReachableViaWiFi];
|
||||
}
|
||||
|
||||
if(bookmark != nil)
|
||||
{
|
||||
// create rdp session
|
||||
RDPSession* session = [[[RDPSession alloc] initWithBookmark:bookmark] autorelease];
|
||||
UIViewController* ctrl = [[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView" bundle:nil session:session];
|
||||
[ctrl setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:ctrl animated:YES];
|
||||
[_active_sessions addObject:session];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)tableView:(UITableView*)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
// get the bookmark
|
||||
NSString* bookmark_editor_title = NSLocalizedString(@"Edit Connection", @"Edit Connection title");
|
||||
ComputerBookmark* bookmark = nil;
|
||||
if ([indexPath section] == SECTION_BOOKMARKS)
|
||||
{
|
||||
if ([indexPath row] == 0)
|
||||
{
|
||||
// create a new bookmark and init hostname and label
|
||||
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
|
||||
bookmark_editor_title = NSLocalizedString(@"Add Connection", @"Add Connection title");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_manual_search_result != nil)
|
||||
{
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
// create a new bookmark and init hostname and label
|
||||
NSString* item = [_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
bookmark = [self bookmarkForQuickConnectTo:item];
|
||||
bookmark_editor_title = NSLocalizedString(@"Add Connection", @"Add Connection title");
|
||||
}
|
||||
else
|
||||
bookmark = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
}
|
||||
else
|
||||
bookmark = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]; // -1 because of ADD BOOKMARK entry
|
||||
}
|
||||
}
|
||||
|
||||
// bookmark found? - start the editor
|
||||
if (bookmark != nil)
|
||||
{
|
||||
BookmarkEditorController* editBookmarkController = [[[BookmarkEditorController alloc] initWithBookmark:bookmark] autorelease];
|
||||
[editBookmarkController setHidesBottomBarWhenPushed:YES];
|
||||
[editBookmarkController setTitle:bookmark_editor_title];
|
||||
[editBookmarkController setDelegate:self];
|
||||
[[self navigationController] pushViewController:editBookmarkController animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Search Bar Delegates
|
||||
|
||||
- (BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar
|
||||
{
|
||||
// show cancel button
|
||||
[searchBar setShowsCancelButton:YES animated:YES];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
// clear search result
|
||||
[_tsxconnect_search_result release];
|
||||
_tsxconnect_search_result = nil;
|
||||
[_manual_search_result release];
|
||||
_manual_search_result = nil;
|
||||
|
||||
// clear text and remove cancel button
|
||||
[searchBar setText:@""];
|
||||
[searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)searchBarShouldEndEditing:(UISearchBar*)searchBar
|
||||
{
|
||||
[searchBar setShowsCancelButton:NO animated:YES];
|
||||
|
||||
// re-enable table selection
|
||||
[_tableView setAllowsSelection:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[_searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText
|
||||
{
|
||||
[self performSearch:searchText];
|
||||
[_tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Session handling
|
||||
|
||||
// session was added
|
||||
- (void)sessionDisconnected:(NSNotification*)notification
|
||||
{
|
||||
// remove session from active sessions
|
||||
RDPSession* session = (RDPSession*)[notification object];
|
||||
[_active_sessions removeObject:session];
|
||||
|
||||
// if this view is currently active refresh tsxconnect entries
|
||||
if([[self navigationController] visibleViewController] == self)
|
||||
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_SESSIONS] withRowAnimation:UITableViewRowAnimationNone];
|
||||
|
||||
// if session's bookmark is not in the bookmark list ask the user if he wants to add it
|
||||
// (this happens if the session is created using the quick connect feature)
|
||||
if (![[session bookmark] isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")] &&
|
||||
![_manual_bookmarks containsObject:[session bookmark]])
|
||||
{
|
||||
// retain the bookmark in case we want to save it later
|
||||
_temporary_bookmark = [[session bookmark] retain];
|
||||
|
||||
// ask the user if he wants to save the bookmark
|
||||
NSString* title = NSLocalizedString(@"Save Connection Settings?", @"Save connection settings title");
|
||||
NSString* message = NSLocalizedString(@"Your Connection Settings have not been saved. Do you want to save them?", @"Save connection settings message");
|
||||
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self
|
||||
cancelButtonTitle:NSLocalizedString(@"Yes", @"Yes Button") otherButtonTitles:NSLocalizedString(@"No", @"No Button"), nil];
|
||||
[alert show];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sessionFailedToConnect:(NSNotification*)notification
|
||||
{
|
||||
// remove session from active sessions
|
||||
RDPSession* session = (RDPSession*)[notification object];
|
||||
[_active_sessions removeObject:session];
|
||||
|
||||
// display error toast
|
||||
[[self view] makeToast:NSLocalizedString(@"Failed to connect to session!", @"Failed to connect error message") duration:ToastDurationNormal position:@"center"];
|
||||
}
|
||||
|
||||
#pragma mark - UIAlertView delegates
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
// yes clicked?
|
||||
if (buttonIndex == 0 && _temporary_bookmark)
|
||||
{
|
||||
[_manual_bookmarks addObject:_temporary_bookmark];
|
||||
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_BOOKMARKS] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
[_temporary_bookmark autorelease];
|
||||
_temporary_bookmark = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Reachability notification
|
||||
- (void)reachabilityChanged:(NSNotification*)notification
|
||||
{
|
||||
// no matter how the network changed - we will disconnect
|
||||
// disconnect session (if there is any)
|
||||
if ([_active_sessions count] > 0)
|
||||
{
|
||||
RDPSession* session = [_active_sessions objectAtIndex:0];
|
||||
[session disconnect];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - BookmarkEditorController delegate
|
||||
|
||||
- (void)commitBookmark:(ComputerBookmark *)bookmark
|
||||
{
|
||||
// if we got a manual bookmark that is not in the list yet - add it
|
||||
if (![_manual_bookmarks containsObject:bookmark])
|
||||
[_manual_bookmarks addObject:bookmark];
|
||||
|
||||
// remove any quick connect history entry with the same hostname
|
||||
NSString* hostname = [[bookmark params] StringForKey:@"hostname"];
|
||||
if ([_connection_history containsObject:hostname])
|
||||
{
|
||||
[_connection_history removeObject:hostname];
|
||||
[self scheduleWriteConnectionHistoryToDataStore];
|
||||
}
|
||||
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
}
|
||||
|
||||
- (IBAction)disconnectButtonPressed:(id)sender
|
||||
{
|
||||
// disconnect session and refresh table view
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[sender tag]];
|
||||
[session disconnect];
|
||||
}
|
||||
|
||||
#pragma mark - Misc functions
|
||||
|
||||
- (BOOL)hasNoBookmarks
|
||||
{
|
||||
return ([_manual_bookmarks count] == 0 && [_tsxconnect_bookmarks count] == 0);
|
||||
}
|
||||
|
||||
- (UIButton*)disclosureButtonWithImage:(UIImage*)image
|
||||
{
|
||||
// we make the button a little bit bigger (image widht * 2, height + 10) so that the user doesn't accidentally connect to the bookmark ...
|
||||
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[button setFrame:CGRectMake(0, 0, [image size].width * 2, [image size].height + 10)];
|
||||
[button setImage:image forState:UIControlStateNormal];
|
||||
[button addTarget:self action:@selector(accessoryButtonTapped:withEvent:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[button setUserInteractionEnabled:YES];
|
||||
return button;
|
||||
}
|
||||
|
||||
- (void)performSearch:(NSString*)searchText
|
||||
{
|
||||
[_manual_search_result autorelease];
|
||||
[_tsxconnect_search_result autorelease];
|
||||
|
||||
if([searchText length] > 0)
|
||||
{
|
||||
_manual_search_result = [FilterBookmarks(_manual_bookmarks, [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) retain];
|
||||
_tsxconnect_search_result = [FilterBookmarks(_tsxconnect_bookmarks, [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) retain];
|
||||
_history_search_result = [FilterHistory(_connection_history, searchText) retain];
|
||||
}
|
||||
else
|
||||
{
|
||||
_history_search_result = nil;
|
||||
_tsxconnect_search_result = nil;
|
||||
_manual_search_result = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (int)bookmarkIndexFromIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
return [indexPath row] - ((_history_search_result != nil) ? [_history_search_result count] : 0) - 1;
|
||||
}
|
||||
|
||||
- (int)historyIndexFromIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
return [indexPath row] - 1;
|
||||
}
|
||||
|
||||
- (BOOL)isIndexPathToHistoryItem:(NSIndexPath*)indexPath
|
||||
{
|
||||
return (([indexPath row] - 1) < [_history_search_result count]);
|
||||
}
|
||||
|
||||
- (ComputerBookmark*)bookmarkForQuickConnectTo:(NSString*)host
|
||||
{
|
||||
ComputerBookmark* bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
|
||||
[bookmark setLabel:host];
|
||||
[[bookmark params] setValue:host forKey:@"hostname"];
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
#pragma mark - Persisting bookmarks
|
||||
|
||||
- (void)scheduleWriteBookmarksToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[self writeBookmarksToDataStore];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)writeBookmarksToDataStore
|
||||
{
|
||||
[self writeManualBookmarksToDataStore];
|
||||
}
|
||||
|
||||
- (void)scheduleWriteManualBookmarksToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(writeManualBookmarksToDataStore) object:nil] autorelease]];
|
||||
}
|
||||
|
||||
- (void)writeManualBookmarksToDataStore
|
||||
{
|
||||
[self writeArray:_manual_bookmarks toDataStoreURL:[self manualBookmarksDataStoreURL]];
|
||||
}
|
||||
|
||||
- (void)scheduleWriteConnectionHistoryToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(writeConnectionHistoryToDataStore) object:nil] autorelease]];
|
||||
}
|
||||
|
||||
- (void)writeConnectionHistoryToDataStore
|
||||
{
|
||||
[self writeArray:_connection_history toDataStoreURL:[self connectionHistoryDataStoreURL]];
|
||||
}
|
||||
|
||||
- (void)writeArray:(NSArray*)bookmarks toDataStoreURL:(NSURL*)url
|
||||
{
|
||||
NSData* archived_data = [NSKeyedArchiver archivedDataWithRootObject:bookmarks];
|
||||
[archived_data writeToURL:url atomically:YES];
|
||||
}
|
||||
|
||||
- (void)readManualBookmarksFromDataStore
|
||||
{
|
||||
[_manual_bookmarks autorelease];
|
||||
_manual_bookmarks = [self arrayFromDataStoreURL:[self manualBookmarksDataStoreURL]];
|
||||
|
||||
if(_manual_bookmarks == nil)
|
||||
_manual_bookmarks = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (void)readConnectionHistoryFromDataStore
|
||||
{
|
||||
[_connection_history autorelease];
|
||||
_connection_history = [self arrayFromDataStoreURL:[self connectionHistoryDataStoreURL]];
|
||||
|
||||
if(_connection_history == nil)
|
||||
_connection_history = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (NSMutableArray*)arrayFromDataStoreURL:(NSURL*)url
|
||||
{
|
||||
NSData* archived_data = [NSData dataWithContentsOfURL:url];
|
||||
|
||||
if (!archived_data)
|
||||
return nil;
|
||||
|
||||
return [[NSKeyedUnarchiver unarchiveObjectWithData:archived_data] retain];
|
||||
}
|
||||
|
||||
- (NSURL*)manualBookmarksDataStoreURL
|
||||
{
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"com.thinstuff.tsx-rdc-ios.bookmarks.plist"]];
|
||||
}
|
||||
|
||||
- (NSURL*)connectionHistoryDataStoreURL
|
||||
{
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"com.thinstuff.tsx-rdc-ios.connection_history.plist"]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Controller to edit bookmark credentials
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface CredentialsEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
}
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Controller to edit bookmark credentials
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "CredentialsEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@interface CredentialsEditorController ()
|
||||
|
||||
@end
|
||||
|
||||
#define SECTION_CREDENTIALS 0
|
||||
#define SECTION_COUNT 1
|
||||
|
||||
@implementation CredentialsEditorController
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:NSLocalizedString(@"Credentials", @"Credentials title")];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// foce any active editing to stop
|
||||
[[self view] endEditing:NO];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_CREDENTIALS:
|
||||
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
if([indexPath row] == 1)
|
||||
cellType = TableCellIdentifierSecretText; // password field
|
||||
else
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// credentials
|
||||
case SECTION_CREDENTIALS:
|
||||
[self initCredentialSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
// updates credentials in the UI
|
||||
- (void)initCredentialSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Username", @"'Username': Bookmark username")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"username"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSecretTextTableViewCell* textCell = (EditSecretTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Password", @"'Password': Bookmark password")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"password"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Domain", @"'Domain': Bookmark domain")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"domain"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update credentials settings
|
||||
case GET_TAG(SECTION_CREDENTIALS, 0):
|
||||
[_params setValue:[textField text] forKey:@"username"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CREDENTIALS, 1):
|
||||
[_params setValue:[textField text] forKey:@"password"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CREDENTIALS, 2):
|
||||
[_params setValue:[textField text] forKey:@"domain"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Credentials input controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RDPSession;
|
||||
|
||||
@interface CredentialsInputController : UIViewController
|
||||
{
|
||||
@private
|
||||
IBOutlet UITextField* _textfield_username;
|
||||
IBOutlet UITextField* _textfield_password;
|
||||
IBOutlet UITextField* _textfield_domain;
|
||||
IBOutlet UIButton* _btn_login;
|
||||
IBOutlet UIButton* _btn_cancel;
|
||||
IBOutlet UIScrollView* _scroll_view;
|
||||
IBOutlet UILabel* _lbl_message;
|
||||
|
||||
RDPSession* _session;
|
||||
NSMutableDictionary* _params;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session params:(NSMutableDictionary*)params;
|
||||
|
||||
@end
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Credentials input controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "CredentialsInputController.h"
|
||||
#import "RDPSession.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation CredentialsInputController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session params:(NSMutableDictionary *)params
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
_session = session;
|
||||
_params = params;
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
|
||||
// on iphone we have the problem that the buttons are hidden by the keyboard
|
||||
// we solve this issue by registering keyboard notification handlers and adjusting the scrollview accordingly
|
||||
if (IsPhone())
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// set localized strings
|
||||
[_lbl_message setText:NSLocalizedString(@"Please provide the missing user information in order to proceed and login.", @"Credentials input view message")];
|
||||
[_textfield_username setPlaceholder:NSLocalizedString(@"Username", @"Credentials Input Username hint")];
|
||||
[_textfield_password setPlaceholder:NSLocalizedString(@"Password", @"Credentials Input Password hint")];
|
||||
[_textfield_domain setPlaceholder:NSLocalizedString(@"Domain", @"Credentials Input Domain hint")];
|
||||
[_btn_login setTitle:NSLocalizedString(@"Login", @"Login Button") forState:UIControlStateNormal];
|
||||
[_btn_cancel setTitle:NSLocalizedString(@"Cancel", @"Cancel Button") forState:UIControlStateNormal];
|
||||
|
||||
// init scrollview content size
|
||||
[_scroll_view setContentSize:[_scroll_view frame].size];
|
||||
|
||||
// set params in the view
|
||||
[_textfield_username setText:[_params valueForKey:@"username"]];
|
||||
[_textfield_password setText:[_params valueForKey:@"password"]];
|
||||
[_textfield_domain setText:[_params valueForKey:@"domain"]];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
// set signal
|
||||
[[_session uiRequestCompleted] signal];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark iOS Keyboard Notification Handlers
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_scroll_view frame];
|
||||
frame.size.height -= keyboardFrame.size.height;
|
||||
[_scroll_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_scroll_view frame];
|
||||
frame.size.height += keyboardFrame.size.height;
|
||||
[_scroll_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (IBAction)loginPressed:(id)sender
|
||||
{
|
||||
// read input back in
|
||||
[_params setValue:[_textfield_username text] forKey:@"username"];
|
||||
[_params setValue:[_textfield_password text] forKey:@"password"];
|
||||
[_params setValue:[_textfield_domain text] forKey:@"domain"];
|
||||
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)cancelPressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Basic interface for settings editors
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "EditTextTableViewCell.h"
|
||||
#import "EditFlagTableViewCell.h"
|
||||
#import "EditSelectionTableViewCell.h"
|
||||
#import "EditSubEditTableViewCell.h"
|
||||
#import "EditSecretTextTableViewCell.h"
|
||||
#import "EditButtonTableViewCell.h"
|
||||
|
||||
extern NSString* TableCellIdentifierText;
|
||||
extern NSString* TableCellIdentifierSecretText;
|
||||
extern NSString* TableCellIdentifierYesNo;
|
||||
extern NSString* TableCellIdentifierSelection;
|
||||
extern NSString* TableCellIdentifierSubEditor;
|
||||
extern NSString* TableCellIdentifierMultiChoice;
|
||||
extern NSString* TableCellIdentifierButton;
|
||||
|
||||
@interface EditorBaseController : UITableViewController <UITextFieldDelegate>
|
||||
{
|
||||
@private
|
||||
IBOutlet EditTextTableViewCell* _textTableViewCell;
|
||||
IBOutlet EditSecretTextTableViewCell* _secretTextTableViewCell;
|
||||
IBOutlet EditFlagTableViewCell* _flagTableViewCell;
|
||||
IBOutlet EditSelectionTableViewCell* _selectionTableViewCell;
|
||||
IBOutlet EditSubEditTableViewCell* _subEditTableViewCell;
|
||||
IBOutlet EditButtonTableViewCell* _buttonTableViewCell;
|
||||
}
|
||||
|
||||
// returns one of the requested table view cells
|
||||
- (UITableViewCell*)tableViewCellFromIdentifier:(NSString*)identifier;
|
||||
|
||||
// Adjust text input cells label/textfield widht according to the label's text size
|
||||
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell*)cell;
|
||||
|
||||
@end
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Basic interface for settings editors
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@interface EditorBaseController ()
|
||||
|
||||
@end
|
||||
|
||||
NSString* TableCellIdentifierText = @"cellIdText";
|
||||
NSString* TableCellIdentifierSecretText = @"cellIdSecretText";
|
||||
NSString* TableCellIdentifierYesNo = @"cellIdYesNo";
|
||||
NSString* TableCellIdentifierSelection = @"cellIdSelection";
|
||||
NSString* TableCellIdentifierSubEditor = @"cellIdSubEditor";
|
||||
NSString* TableCellIdentifierMultiChoice = @"cellIdMultiChoice";
|
||||
NSString* TableCellIdentifierButton = @"cellIdButton";
|
||||
|
||||
@implementation EditorBaseController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Create table view cells
|
||||
- (UITableViewCell*)tableViewCellFromIdentifier:(NSString*)identifier
|
||||
{
|
||||
// try to reuse a cell
|
||||
UITableViewCell* cell = [[self tableView] dequeueReusableCellWithIdentifier:identifier];
|
||||
if (cell != nil)
|
||||
return cell;
|
||||
|
||||
// we have to create a new cell
|
||||
if ([identifier isEqualToString:TableCellIdentifierText])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditTextTableViewCell" owner:self options:nil];
|
||||
cell = _textTableViewCell;
|
||||
_textTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSecretText])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSecretTextTableViewCell" owner:self options:nil];
|
||||
cell = _secretTextTableViewCell;
|
||||
_secretTextTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierYesNo])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditFlagTableViewCell" owner:self options:nil];
|
||||
cell = _flagTableViewCell;
|
||||
_flagTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSelection])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSelectionTableViewCell" owner:self options:nil];
|
||||
cell = _selectionTableViewCell;
|
||||
_selectionTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSubEditor])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSubEditTableViewCell" owner:self options:nil];
|
||||
cell = _subEditTableViewCell;
|
||||
_subEditTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierButton])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditButtonTableViewCell" owner:self options:nil];
|
||||
cell = _buttonTableViewCell;
|
||||
_buttonTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierMultiChoice])
|
||||
{
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier] autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert(false, @"Unknown table cell identifier");
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Utility functions
|
||||
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell*)cell
|
||||
{
|
||||
UILabel* label = [cell label];
|
||||
UITextField* textField = [cell textfield];
|
||||
|
||||
// adjust label
|
||||
CGFloat width = [[label text] sizeWithFont:[label font]].width;
|
||||
CGRect frame = [label frame];
|
||||
CGFloat delta = width - frame.size.width;
|
||||
frame.size.width = width;
|
||||
[label setFrame:frame];
|
||||
|
||||
// adjust text field
|
||||
frame = [textField frame];
|
||||
frame.origin.x += delta;
|
||||
frame.size.width -= delta;
|
||||
[textField setFrame:frame];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Generic controller to select a single item from a list of options
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface EditorSelectionController : EditorBaseController
|
||||
{
|
||||
ConnectionParams* _params;
|
||||
|
||||
// array with entries in connection parameters that are altered
|
||||
NSArray* _entries;
|
||||
|
||||
// array with dictionaries containing label/value pairs that represent the available values for each entry
|
||||
NSArray* _selections;
|
||||
|
||||
// current selections
|
||||
NSMutableArray* _cur_selections;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params entries:(NSArray*)entries selections:(NSArray*)selections;
|
||||
|
||||
@end
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
Generic controller to select a single item from a list of options
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorSelectionController.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "OrderedDictionary.h"
|
||||
|
||||
@interface EditorSelectionController (Private)
|
||||
- (OrderedDictionary*)selectionForIndex:(int)index;
|
||||
@end
|
||||
|
||||
@implementation EditorSelectionController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params entries:(NSArray *)entries selections:(NSArray *)selections
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self)
|
||||
{
|
||||
_params = [params retain];
|
||||
_entries = [entries retain];
|
||||
_selections = [selections retain];
|
||||
|
||||
// allocate and init current selections array
|
||||
_cur_selections = [[NSMutableArray alloc] initWithCapacity:[_entries count]];
|
||||
for (int i = 0; i < [entries count]; ++i)
|
||||
{
|
||||
NSString* entry = [entries objectAtIndex:i];
|
||||
if([_params hasValueForKeyPath:entry])
|
||||
{
|
||||
NSUInteger idx = [(OrderedDictionary*)[selections objectAtIndex:i] indexForValue:[NSNumber numberWithInt:[_params intForKeyPath:entry]]];
|
||||
[_cur_selections addObject:[NSNumber numberWithInt:(idx != NSNotFound ? idx : 0)]];
|
||||
}
|
||||
else
|
||||
[_cur_selections addObject:[NSNumber numberWithInt:0]];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
[_params autorelease];
|
||||
[_entries autorelease];
|
||||
[_selections autorelease];
|
||||
[_cur_selections autorelease];
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
// Return the number of sections.
|
||||
return [_entries count];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
// Return the number of rows in the section.
|
||||
return [[self selectionForIndex:section] count];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
|
||||
// get selection
|
||||
OrderedDictionary* selection = [self selectionForIndex:[indexPath section]];
|
||||
|
||||
// set cell properties
|
||||
[[cell textLabel] setText:[selection keyAtIndex:[indexPath row]]];
|
||||
|
||||
// set default checkmark
|
||||
if([indexPath row] == [[_cur_selections objectAtIndex:[indexPath section]] intValue])
|
||||
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
|
||||
else
|
||||
[cell setAccessoryType:UITableViewCellAccessoryNone];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// has selection change?
|
||||
int cur_selection = [[_cur_selections objectAtIndex:[indexPath section]] intValue];
|
||||
if([indexPath row] != cur_selection)
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSIndexPath* oldIndexPath = [NSIndexPath indexPathForRow:cur_selection inSection:[indexPath section]];
|
||||
|
||||
// clear old checkmark
|
||||
UITableViewCell* old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
|
||||
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
|
||||
// set new checkmark
|
||||
UITableViewCell* new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
|
||||
// get value from selection dictionary
|
||||
OrderedDictionary* dict = [self selectionForIndex:[indexPath section]];
|
||||
int sel_value = [[dict valueForKey:[dict keyAtIndex:[indexPath row]]] intValue];
|
||||
|
||||
// update selection index and params value
|
||||
[_cur_selections replaceObjectAtIndex:[indexPath section] withObject:[NSNumber numberWithInt:[indexPath row]]];
|
||||
[_params setInt:sel_value forKeyPath:[_entries objectAtIndex:[indexPath section]]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Convenience functions
|
||||
|
||||
- (OrderedDictionary*)selectionForIndex:(int)index
|
||||
{
|
||||
return (OrderedDictionary*)[_selections objectAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
Password Encryption Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Encryptor.h"
|
||||
|
||||
@interface EncryptionController : NSObject
|
||||
{
|
||||
Encryptor* _shared_encryptor;
|
||||
}
|
||||
|
||||
+ (EncryptionController*)sharedEncryptionController;
|
||||
|
||||
// Return a Encryptor suitable for encrypting or decrypting with the master password
|
||||
- (Encryptor*)decryptor;
|
||||
- (Encryptor*)encryptor;
|
||||
|
||||
@end
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Password Encryption Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EncryptionController.h"
|
||||
#import "SFHFKeychainUtils.h"
|
||||
|
||||
@interface EncryptionController (Private)
|
||||
|
||||
- (BOOL)verifyPassword:(Encryptor*)decryptor;
|
||||
- (NSData*)encryptedVerificationData;
|
||||
- (void)setEncryptedVerificationData:(Encryptor*)encryptor;
|
||||
|
||||
- (NSString*)keychainServerName;
|
||||
- (NSString*)keychainUsername;
|
||||
- (void)setKeychainPassword:(NSString*)password;
|
||||
- (NSString*)keychainPassword;
|
||||
- (NSString*)keychainDefaultPassword;
|
||||
|
||||
@end
|
||||
|
||||
static EncryptionController* _shared_encryption_controller = nil;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation EncryptionController
|
||||
|
||||
+ (EncryptionController*)sharedEncryptionController
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (_shared_encryption_controller == nil)
|
||||
_shared_encryption_controller = [[EncryptionController alloc] init];
|
||||
}
|
||||
|
||||
return _shared_encryption_controller;
|
||||
}
|
||||
|
||||
#pragma mark Getting an encryptor or decryptor
|
||||
|
||||
- (Encryptor*)encryptor
|
||||
{
|
||||
if (_shared_encryptor)
|
||||
return _shared_encryptor;
|
||||
|
||||
NSString* saved_password = [self keychainPassword];
|
||||
if (saved_password == nil)
|
||||
{
|
||||
saved_password = [self keychainDefaultPassword];
|
||||
Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
|
||||
[self setEncryptedVerificationData:encryptor];
|
||||
_shared_encryptor = [encryptor retain];
|
||||
}
|
||||
else
|
||||
{
|
||||
Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
|
||||
if ([self verifyPassword:encryptor])
|
||||
_shared_encryptor = [encryptor retain];
|
||||
}
|
||||
|
||||
return _shared_encryptor;
|
||||
}
|
||||
|
||||
// For the current implementation, decryptors and encryptors are equivilant.
|
||||
- (Encryptor*)decryptor { return [self encryptor]; }
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation EncryptionController (Private)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Keychain password storage
|
||||
|
||||
- (NSString*)keychainServerName
|
||||
{
|
||||
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
}
|
||||
|
||||
- (NSString*)keychainUsername
|
||||
{
|
||||
return @"master.password";
|
||||
}
|
||||
|
||||
- (void)setKeychainPassword:(NSString*)password
|
||||
{
|
||||
NSError* error;
|
||||
if (password == nil)
|
||||
{
|
||||
[SFHFKeychainUtils deleteItemForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
|
||||
return;
|
||||
}
|
||||
|
||||
[SFHFKeychainUtils storeUsername:[self keychainUsername] andPassword:password forServerName:[self keychainServerName] updateExisting:YES error:&error];
|
||||
}
|
||||
|
||||
- (NSString*)keychainPassword
|
||||
{
|
||||
NSError* error;
|
||||
return [SFHFKeychainUtils getPasswordForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
|
||||
}
|
||||
|
||||
- (NSString*)keychainDefaultPassword
|
||||
{
|
||||
return [[UIDevice currentDevice] uniqueIdentifier];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Verification of encryption key against verification data
|
||||
|
||||
- (BOOL)verifyPassword:(Encryptor*)decryptor
|
||||
{
|
||||
return [[decryptor plaintextPassword] isEqualToString:[decryptor decryptString:[self encryptedVerificationData]]];
|
||||
}
|
||||
|
||||
- (NSData*)encryptedVerificationData
|
||||
{
|
||||
return [[NSUserDefaults standardUserDefaults] dataForKey:@"TSXMasterPasswordVerification"];
|
||||
}
|
||||
|
||||
- (void)setEncryptedVerificationData:(Encryptor*)encryptor
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[encryptor encryptString:[encryptor plaintextPassword]] forKey:@"TSXMasterPasswordVerification"];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
Application help controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface HelpController : UIViewController <UIWebViewDelegate>
|
||||
{
|
||||
UIWebView* webView;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Application help controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "HelpController.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation HelpController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
// set title and tab-bar image
|
||||
[self setTitle:NSLocalizedString(@"Help", @"Help Controller title")];
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_help" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Help", @"Tabbar item help") image:tabBarIcon tag:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
|
||||
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
|
||||
[webView setAutoresizesSubviews:YES];
|
||||
[webView setDelegate:self];
|
||||
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
|
||||
[self setView:webView];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString *filename = (IsPhone() ? @"gestures_phone" : @"gestures");
|
||||
NSString *htmlString = [[[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:@"html" inDirectory:@"help_page"] encoding:NSUTF8StringEncoding error:nil] autorelease];
|
||||
|
||||
[webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"help_page"]]];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIWebView callbacks
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
if([[request URL] isFileURL])
|
||||
return YES;
|
||||
|
||||
if(navigationType == UIWebViewNavigationTypeLinkClicked)
|
||||
{
|
||||
NSString* lastClickedLink = [[request URL] absoluteString];
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"External Link"
|
||||
message:[NSString stringWithFormat:@"Open [%@] in Browser?", lastClickedLink]
|
||||
delegate:self
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:@"No", nil];
|
||||
[alert show];
|
||||
[alert release];
|
||||
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
main tabbar controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface MainTabBarController : UITabBarController {
|
||||
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
main tabbar controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "MainTabBarController.h"
|
||||
|
||||
|
||||
@implementation MainTabBarController
|
||||
|
||||
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
controller for performance settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface PerformanceEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ConnectionParams* _params;
|
||||
NSString* _keyPath;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params;
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
|
||||
@end
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
controller for performance settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "PerformanceEditorController.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@interface PerformanceEditorController (Private)
|
||||
-(NSString*)keyPathForKey:(NSString*)key;
|
||||
@end
|
||||
|
||||
@implementation PerformanceEditorController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params
|
||||
{
|
||||
return [self initWithConnectionParams:params keyPath:nil];
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self) {
|
||||
_params = [params retain];
|
||||
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(NSString*)keyPathForKey:(NSString*)key
|
||||
{
|
||||
if (_keyPath)
|
||||
return [_keyPath stringByAppendingFormat:@".%@", key];
|
||||
return key;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return NSLocalizedString(@"Performance Settings", @"'Performance Settings': performance settings header");
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// get the table view cell
|
||||
EditFlagTableViewCell *cell = (EditFlagTableViewCell*)[self tableViewCellFromIdentifier:TableCellIdentifierYesNo];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"RemoteFX", @"RemoteFX performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_remotefx"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Desktop Background", @"Desktop background performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_show_desktop"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Font Smoothing", @"Font smoothing performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_font_smoothing"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Desktop Composition", @"Desktop composition performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_desktop_composition"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Window contents while dragging", @"Window Dragging performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_window_dragging"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Menu Animation", @"Menu Animations performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_menu_animation"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Visual Styles", @"Use Themes performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_windows_themes"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
[[cell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[cell toggle] addTarget:self action:@selector(togglePerformanceSetting:) forControlEvents:UIControlEventValueChanged];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)togglePerformanceSetting:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch(valueSwitch.tag)
|
||||
{
|
||||
case GET_TAG(0, 0):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_remotefx"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 1):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_show_desktop"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 2):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_font_smoothing"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 3):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_desktop_composition"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 4):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_window_dragging"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 5):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_menu_animation"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 6):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_windows_themes"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
RDP Session View Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RDPSession.h"
|
||||
#import "RDPKeyboard.h"
|
||||
#import "RDPSessionView.h"
|
||||
#import "TouchPointerView.h"
|
||||
#import "AdvancedKeyboardView.h"
|
||||
|
||||
@interface RDPSessionViewController : UIViewController <RDPSessionDelegate, TouchPointerDelegate, AdvancedKeyboardDelegate, RDPKeyboardDelegate, UIScrollViewDelegate, UITextFieldDelegate, UIAlertViewDelegate>
|
||||
{
|
||||
// scrollview that hosts the rdp session view
|
||||
IBOutlet UIScrollView* _session_scrollview;
|
||||
|
||||
// rdp session view
|
||||
IBOutlet RDPSessionView* _session_view;
|
||||
|
||||
// touch pointer view
|
||||
IBOutlet TouchPointerView* _touchpointer_view;
|
||||
BOOL _autoscroll_with_touchpointer;
|
||||
BOOL _is_autoscrolling;
|
||||
|
||||
// rdp session toolbar
|
||||
IBOutlet UIToolbar* _session_toolbar;
|
||||
BOOL _session_toolbar_visible;
|
||||
|
||||
// dummy text field used to display the keyboard
|
||||
IBOutlet UITextField* _dummy_textfield;
|
||||
|
||||
// connecting view and the controls within that view
|
||||
IBOutlet UIView* _connecting_view;
|
||||
IBOutlet UILabel* _lbl_connecting;
|
||||
IBOutlet UIActivityIndicatorView* _connecting_indicator_view;
|
||||
IBOutlet UIButton* _cancel_connect_button;
|
||||
|
||||
// extended keyboard toolbar
|
||||
UIToolbar* _keyboard_toolbar;
|
||||
|
||||
// rdp session
|
||||
RDPSession* _session;
|
||||
BOOL _session_initilized;
|
||||
|
||||
// flag that indicates whether the keyboard is visible or not
|
||||
BOOL _keyboard_visible;
|
||||
|
||||
// flag to switch between left/right mouse button mode
|
||||
BOOL _toggle_mouse_button;
|
||||
|
||||
// keyboard extension view
|
||||
AdvancedKeyboardView* _advanced_keyboard_view;
|
||||
BOOL _advanced_keyboard_visible;
|
||||
BOOL _requesting_advanced_keyboard;
|
||||
|
||||
// delayed mouse move event sending
|
||||
NSTimer* _mouse_move_event_timer;
|
||||
int _mouse_move_events_skipped;
|
||||
CGPoint _prev_long_press_position;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session;
|
||||
|
||||
@end
|
|
@ -0,0 +1,980 @@
|
|||
/*
|
||||
RDP Session View Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "RDPSessionViewController.h"
|
||||
#import "RDPKeyboard.h"
|
||||
#import "Utils.h"
|
||||
#import "Toast+UIView.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "CredentialsInputController.h"
|
||||
#import "VerifyCertificateController.h"
|
||||
|
||||
#define TOOLBAR_HEIGHT 30
|
||||
|
||||
#define AUTOSCROLLDISTANCE 20
|
||||
#define AUTOSCROLLTIMEOUT 0.05
|
||||
|
||||
@interface RDPSessionViewController (Private)
|
||||
-(void)showSessionToolbar:(BOOL)show;
|
||||
-(UIToolbar*)keyboardToolbar;
|
||||
-(void)initGestureRecognizers;
|
||||
- (void)suspendSession;
|
||||
- (NSDictionary*)eventDescriptorForMouseEvent:(int)event position:(CGPoint)position;
|
||||
- (void)handleMouseMoveForPosition:(CGPoint)position;
|
||||
@end
|
||||
|
||||
|
||||
@implementation RDPSessionViewController
|
||||
|
||||
#pragma mark class methods
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self)
|
||||
{
|
||||
_session = [session retain];
|
||||
[_session setDelegate:self];
|
||||
_session_initilized = NO;
|
||||
|
||||
_mouse_move_events_skipped = 0;
|
||||
_mouse_move_event_timer = nil;
|
||||
|
||||
_advanced_keyboard_view = nil;
|
||||
_advanced_keyboard_visible = NO;
|
||||
_requesting_advanced_keyboard = NO;
|
||||
|
||||
_session_toolbar_visible = NO;
|
||||
|
||||
_toggle_mouse_button = NO;
|
||||
|
||||
_autoscroll_with_touchpointer = [[NSUserDefaults standardUserDefaults] boolForKey:@"ui.auto_scroll_touchpointer"];
|
||||
_is_autoscrolling = NO;
|
||||
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationStopped:finished:context:)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
// load default view and set background color and resizing mask
|
||||
[super loadView];
|
||||
|
||||
// init keyboard handling vars and register required notification handlers
|
||||
_keyboard_visible = NO;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil];
|
||||
|
||||
// init keyboard toolbar
|
||||
_keyboard_toolbar = [[self keyboardToolbar] retain];
|
||||
[_dummy_textfield setInputAccessoryView:_keyboard_toolbar];
|
||||
|
||||
// init gesture recognizers
|
||||
[self initGestureRecognizers];
|
||||
|
||||
// hide session toolbar
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
}
|
||||
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
|
||||
{
|
||||
if (![_touchpointer_view isHidden])
|
||||
[_touchpointer_view ensurePointerIsVisible];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc. that aren't in use.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload {
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// hide navigation bar and (if enabled) the status bar
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_status_bar"])
|
||||
{
|
||||
if(animated == YES)
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
|
||||
else
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
|
||||
}
|
||||
[[self navigationController] setNavigationBarHidden:YES animated:animated];
|
||||
|
||||
// if sesssion is suspended - notify that we got a new bitmap context
|
||||
if ([_session isSuspended])
|
||||
[self sessionBitmapContextWillChange:_session];
|
||||
|
||||
// init keyboard
|
||||
[[RDPKeyboard getSharedRDPKeyboard] initWithSession:_session delegate:self];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (!_session_initilized)
|
||||
{
|
||||
if ([_session isSuspended])
|
||||
{
|
||||
[_session resume];
|
||||
[self sessionBitmapContextDidChange:_session];
|
||||
[_session_view setNeedsDisplay];
|
||||
}
|
||||
else
|
||||
[_session connect];
|
||||
|
||||
_session_initilized = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// show navigation and status bar again
|
||||
if(animated == YES)
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
|
||||
else
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
|
||||
[[self navigationController] setNavigationBarHidden:NO animated:animated];
|
||||
|
||||
// reset all modifier keys on rdp keyboard
|
||||
[[RDPKeyboard getSharedRDPKeyboard] reset];
|
||||
|
||||
// hide toolbar and keyboard
|
||||
[self showSessionToolbar:NO];
|
||||
[_dummy_textfield resignFirstResponder];
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
// remove any observers
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
// the session lives on longer so set the delegate to nil
|
||||
[_session setDelegate:nil];
|
||||
|
||||
[_advanced_keyboard_view release];
|
||||
[_keyboard_toolbar release];
|
||||
[_session release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark ScrollView delegate methods
|
||||
|
||||
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
|
||||
{
|
||||
return _session_view;
|
||||
}
|
||||
|
||||
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
|
||||
{
|
||||
NSLog(@"New zoom scale: %f", scale);
|
||||
[_session_view setNeedsDisplay];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark TextField delegate methods
|
||||
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
|
||||
{
|
||||
_keyboard_visible = YES;
|
||||
_advanced_keyboard_visible = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
_keyboard_visible = NO;
|
||||
_advanced_keyboard_visible = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
if([string length] > 0)
|
||||
{
|
||||
for(int i = 0 ; i < [string length] ; i++)
|
||||
{
|
||||
NSString *characterTyped = [string substringWithRange:NSMakeRange(i, 1)];
|
||||
unichar curChar = [characterTyped characterAtIndex:0];
|
||||
|
||||
// special handling for return/enter key
|
||||
if(curChar == '\n')
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendEnterKeyStroke];
|
||||
else
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendUnicode:curChar];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendBackspaceKeyStroke];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark AdvancedKeyboardDelegate functions
|
||||
-(void)advancedKeyPressedVKey:(int)key
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendVirtualKeyCode:key];
|
||||
}
|
||||
|
||||
-(void)advancedKeyPressedUnicode:(int)key
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendUnicode:key];
|
||||
}
|
||||
|
||||
#pragma mark - RDP keyboard handler
|
||||
|
||||
- (void)modifiersChangedForKeyboard:(RDPKeyboard *)keyboard
|
||||
{
|
||||
UIBarButtonItem* curItem;
|
||||
|
||||
// shift button (only on iPad)
|
||||
int objectIdx = 0;
|
||||
if (IsPad())
|
||||
{
|
||||
objectIdx = 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard shiftPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
}
|
||||
|
||||
// ctrl button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard ctrlPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
|
||||
// win button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard winPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
|
||||
// alt button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard altPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark RDPSessionDelegate functions
|
||||
|
||||
- (void)session:(RDPSession*)session didFailToConnect:(int)reason
|
||||
{
|
||||
// remove and release connecting view
|
||||
[_connecting_indicator_view stopAnimating];
|
||||
[_connecting_view removeFromSuperview];
|
||||
[_connecting_view autorelease];
|
||||
|
||||
// return to bookmark list
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)sessionWillConnect:(RDPSession*)session
|
||||
{
|
||||
// load connecting view
|
||||
[[NSBundle mainBundle] loadNibNamed:@"RDPConnectingView" owner:self options:nil];
|
||||
|
||||
// set strings
|
||||
[_lbl_connecting setText:NSLocalizedString(@"Connecting", @"Connecting progress view - label")];
|
||||
[_cancel_connect_button setTitle:NSLocalizedString(@"Cancel", @"Cancel Button") forState:UIControlStateNormal];
|
||||
|
||||
// center view and give it round corners
|
||||
[_connecting_view setCenter:[[self view] center]];
|
||||
[[_connecting_view layer] setCornerRadius:10];
|
||||
|
||||
// display connecting view and start indicator
|
||||
[[self view] addSubview:_connecting_view];
|
||||
[_connecting_indicator_view startAnimating];
|
||||
}
|
||||
|
||||
- (void)sessionDidConnect:(RDPSession*)session
|
||||
{
|
||||
// remove and release connecting view
|
||||
[_connecting_indicator_view stopAnimating];
|
||||
[_connecting_view removeFromSuperview];
|
||||
[_connecting_view autorelease];
|
||||
|
||||
// check if session settings changed ...
|
||||
// The 2nd width check is to ignore changes in resolution settings due to the RDVH display bug (refer to RDPSEssion.m for more details)
|
||||
ConnectionParams* orig_params = [session params];
|
||||
rdpSettings* sess_params = [session getSessionParams];
|
||||
if (([orig_params intForKey:@"width"] != sess_params->DesktopWidth && [orig_params intForKey:@"width"] != (sess_params->DesktopWidth + 1)) ||
|
||||
[orig_params intForKey:@"height"] != sess_params->DesktopHeight || [orig_params intForKey:@"colors"] != sess_params->ColorDepth)
|
||||
{
|
||||
// display notification that the session params have been changed by the server
|
||||
NSString* message = [NSString stringWithFormat:NSLocalizedString(@"The server changed the screen settings to %dx%dx%d", @"Screen settings not supported message with width, height and colors parameter"), sess_params->DesktopWidth, sess_params->DesktopHeight, sess_params->ColorDepth];
|
||||
[[self view] makeToast:message duration:ToastDurationNormal position:@"bottom"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sessionWillDisconnect:(RDPSession*)session
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionDidDisconnect:(RDPSession*)session
|
||||
{
|
||||
// return to bookmark list
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextWillChange:(RDPSession*)session
|
||||
{
|
||||
// calc new view frame
|
||||
rdpSettings* sess_params = [session getSessionParams];
|
||||
CGRect view_rect = CGRectMake(0, 0, sess_params->DesktopWidth, sess_params->DesktopHeight);
|
||||
|
||||
// reset zoom level and update content size
|
||||
[_session_scrollview setZoomScale:1.0];
|
||||
[_session_scrollview setContentSize:view_rect.size];
|
||||
|
||||
// set session view size
|
||||
[_session_view setFrame:view_rect];
|
||||
|
||||
// show/hide toolbar
|
||||
[_session setToolbarVisible:![[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
|
||||
[self showSessionToolbar:[_session toolbarVisible]];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextDidChange:(RDPSession*)session
|
||||
{
|
||||
// associate view with session
|
||||
[_session_view setSession:session];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession*)session needsRedrawInRect:(CGRect)rect
|
||||
{
|
||||
[_session_view setNeedsDisplayInRect:rect];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession *)session requestsAuthenticationWithParams:(NSMutableDictionary *)params
|
||||
{
|
||||
CredentialsInputController* view_controller = [[[CredentialsInputController alloc] initWithNibName:@"CredentialsInputView" bundle:nil session:_session params:params] autorelease];
|
||||
[self presentModalViewController:view_controller animated:YES];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession *)session verifyCertificateWithParams:(NSMutableDictionary *)params
|
||||
{
|
||||
VerifyCertificateController* view_controller = [[[VerifyCertificateController alloc] initWithNibName:@"VerifyCertificateView" bundle:nil session:_session params:params] autorelease];
|
||||
[self presentModalViewController:view_controller animated:YES];
|
||||
}
|
||||
|
||||
- (CGSize)sizeForFitScreenForSession:(RDPSession*)session
|
||||
{
|
||||
if (IsPad())
|
||||
return [self view].bounds.size;
|
||||
else
|
||||
{
|
||||
// on phones make a resolution that has a 16:10 ratio with the phone's height
|
||||
CGSize size = [self view].bounds.size;
|
||||
CGFloat maxSize = (size.width > size.height) ? size.width : size.height;
|
||||
return CGSizeMake(maxSize * 1.6f, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showGoProScreen:(RDPSession*)session
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Pro Version", @"Pro version dialog title")
|
||||
message:NSLocalizedString(@"Do you want to buy Thinstuff RDC Pro and enable the full RDP Experience", @"Pro version dialog message") delegate:self cancelButtonTitle:NSLocalizedString(@"No", @"No Button title") otherButtonTitles:NSLocalizedString(@"Yes", @"Yes button title"), nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard Toolbar Handlers
|
||||
|
||||
-(void)showAdvancedKeyboardAnimated
|
||||
{
|
||||
// calc initial and final rect of the advanced keyboard view
|
||||
CGRect rect = [[_keyboard_toolbar superview] bounds];
|
||||
rect.origin.y = [_keyboard_toolbar bounds].size.height;
|
||||
rect.size.height -= rect.origin.y;
|
||||
|
||||
// create new view (hidden) and add to host-view of keyboard toolbar
|
||||
_advanced_keyboard_view = [[AdvancedKeyboardView alloc] initWithFrame:CGRectMake(rect.origin.x,
|
||||
[[_keyboard_toolbar superview] bounds].size.height,
|
||||
rect.size.width, rect.size.height) delegate:self];
|
||||
[[_keyboard_toolbar superview] addSubview:_advanced_keyboard_view];
|
||||
// we set autoresize to YES for the keyboard toolbar's superview so that our adv. keyboard view gets properly resized
|
||||
[[_keyboard_toolbar superview] setAutoresizesSubviews:YES];
|
||||
|
||||
// show view with animation
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[_advanced_keyboard_view setFrame:rect];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
-(IBAction)toggleKeyboardWhenOtherVisible:(id)sender
|
||||
{
|
||||
if(_advanced_keyboard_visible == NO)
|
||||
{
|
||||
[self showAdvancedKeyboardAnimated];
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide existing view
|
||||
[UIView beginAnimations:@"hide_advanced_keyboard_view" context:NULL];
|
||||
CGRect rect = [_advanced_keyboard_view frame];
|
||||
rect.origin.y = [[_keyboard_toolbar superview] bounds].size.height;
|
||||
[_advanced_keyboard_view setFrame:rect];
|
||||
[UIView commitAnimations];
|
||||
|
||||
// the view is released in the animationDidStop selector registered in init
|
||||
}
|
||||
|
||||
// toggle flag
|
||||
_advanced_keyboard_visible = !_advanced_keyboard_visible;
|
||||
}
|
||||
|
||||
-(IBAction)toggleWinKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleWinKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleShiftKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleShiftKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleCtrlKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleCtrlKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleAltKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleAltKey];
|
||||
}
|
||||
|
||||
-(IBAction)pressEscKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendEscapeKeyStroke];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark event handlers
|
||||
|
||||
- (void)animationStopped:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context
|
||||
{
|
||||
if ([animationID isEqualToString:@"hide_advanced_keyboard_view"])
|
||||
{
|
||||
// cleanup advanced keyboard view
|
||||
[_advanced_keyboard_view removeFromSuperview];
|
||||
[_advanced_keyboard_view autorelease];
|
||||
_advanced_keyboard_view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)switchSession:(id)sender
|
||||
{
|
||||
[self suspendSession];
|
||||
}
|
||||
|
||||
- (IBAction)toggleKeyboard:(id)sender
|
||||
{
|
||||
if(!_keyboard_visible)
|
||||
[_dummy_textfield becomeFirstResponder];
|
||||
else
|
||||
[_dummy_textfield resignFirstResponder];
|
||||
}
|
||||
|
||||
- (IBAction)toggleExtKeyboard:(id)sender
|
||||
{
|
||||
// if the sys kb is shown but not the advanced kb then toggle the advanced kb
|
||||
if(_keyboard_visible && !_advanced_keyboard_visible)
|
||||
[self toggleKeyboardWhenOtherVisible:nil];
|
||||
else
|
||||
{
|
||||
// if not visible request the advanced keyboard view
|
||||
if(_advanced_keyboard_visible == NO)
|
||||
_requesting_advanced_keyboard = YES;
|
||||
[self toggleKeyboard:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleTouchPointer:(id)sender
|
||||
{
|
||||
BOOL toggle_visibilty = ![_touchpointer_view isHidden];
|
||||
[_touchpointer_view setHidden:toggle_visibilty];
|
||||
if(toggle_visibilty)
|
||||
[_session_scrollview setContentInset:UIEdgeInsetsZero];
|
||||
else
|
||||
[_session_scrollview setContentInset:[_touchpointer_view getEdgeInsets]];
|
||||
}
|
||||
|
||||
- (IBAction)disconnectSession:(id)sender
|
||||
{
|
||||
[_session disconnect];
|
||||
}
|
||||
|
||||
|
||||
-(IBAction)cancelButtonPressed:(id)sender
|
||||
{
|
||||
[_session disconnect];
|
||||
}
|
||||
|
||||
#pragma mark In-App purchase transaction notification handlers
|
||||
|
||||
- (void)onTransactionSuccess:(NSNotification*)notification
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transaction Succeeded", @"Pro version bought dialog title")
|
||||
message:NSLocalizedString(@"Thanks for buying Thinstuff RDC Pro. In order for the purchase to take effect please reconnect your current session.", @"Pro version bought dialog message") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button title") otherButtonTitles:nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
- (void)onTransactionFailed:(NSNotification*)notification
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transaction Failed", @"Pro version buy failed dialog title")
|
||||
message:NSLocalizedString(@"The transaction did not complete successfully!", @"Pro version buy failed dialog message") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button title") otherButtonTitles:nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark iOS Keyboard Notification Handlers
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_session_scrollview frame];
|
||||
frame.size.height -= [[self view] convertRect:keyboardEndFrame toView:nil].size.height;
|
||||
[_session_scrollview setFrame:frame];
|
||||
[_touchpointer_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
|
||||
[_touchpointer_view ensurePointerIsVisible];
|
||||
}
|
||||
|
||||
- (void)keyboardDidShow:(NSNotification *)notification
|
||||
{
|
||||
if(_requesting_advanced_keyboard)
|
||||
{
|
||||
[self showAdvancedKeyboardAnimated];
|
||||
_advanced_keyboard_visible = YES;
|
||||
_requesting_advanced_keyboard = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_session_scrollview frame];
|
||||
frame.size.height += [[self view] convertRect:keyboardEndFrame toView:nil].size.height;
|
||||
[_session_scrollview setFrame:frame];
|
||||
[_touchpointer_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (void)keyboardDidHide:(NSNotification*)notification
|
||||
{
|
||||
// release adanced keyboard view
|
||||
if(_advanced_keyboard_visible == YES)
|
||||
{
|
||||
_advanced_keyboard_visible = NO;
|
||||
[_advanced_keyboard_view removeFromSuperview];
|
||||
[_advanced_keyboard_view autorelease];
|
||||
_advanced_keyboard_view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Gesture handlers
|
||||
|
||||
- (void)handleSingleTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
if (_toggle_mouse_button)
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
|
||||
_toggle_mouse_button = NO;
|
||||
}
|
||||
|
||||
- (void)handleDoubleTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
_toggle_mouse_button = NO;
|
||||
}
|
||||
|
||||
- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
|
||||
if([gesture state] == UIGestureRecognizerStateBegan)
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
else if([gesture state] == UIGestureRecognizerStateChanged)
|
||||
[self handleMouseMoveForPosition:pos];
|
||||
else if([gesture state] == UIGestureRecognizerStateEnded)
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
|
||||
|
||||
- (void)handleDoubleLongPress:(UILongPressGestureRecognizer*)gesture
|
||||
{
|
||||
// this point is mapped against the scroll view because we want to have relative movement to the screen/scrollview
|
||||
CGPoint pos = [gesture locationInView:_session_scrollview];
|
||||
|
||||
if([gesture state] == UIGestureRecognizerStateBegan)
|
||||
_prev_long_press_position = pos;
|
||||
else if([gesture state] == UIGestureRecognizerStateChanged)
|
||||
{
|
||||
int delta = _prev_long_press_position.y - pos.y;
|
||||
|
||||
if(delta > GetScrollGestureDelta())
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(YES) position:pos]];
|
||||
_prev_long_press_position = pos;
|
||||
}
|
||||
else if(delta < -GetScrollGestureDelta())
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(NO) position:pos]];
|
||||
_prev_long_press_position = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)handleSingle2FingersTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
_toggle_mouse_button = !_toggle_mouse_button;
|
||||
}
|
||||
|
||||
-(void)handleSingle3FingersTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
[_session setToolbarVisible:![_session toolbarVisible]];
|
||||
[self showSessionToolbar:[_session toolbarVisible]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Touch Pointer delegates
|
||||
// callback if touch pointer should be closed
|
||||
-(void)touchPointerClose
|
||||
{
|
||||
[self toggleTouchPointer:nil];
|
||||
}
|
||||
|
||||
// callback for a left click action
|
||||
-(void)touchPointerLeftClick:(CGPoint)pos down:(BOOL)down
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(down) position:session_view_pos]];
|
||||
}
|
||||
|
||||
// callback for a right click action
|
||||
-(void)touchPointerRightClick:(CGPoint)pos down:(BOOL)down
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(down) position:session_view_pos]];
|
||||
}
|
||||
|
||||
- (void)doAutoScrolling
|
||||
{
|
||||
int scrollX = 0;
|
||||
int scrollY = 0;
|
||||
CGPoint curPointerPos = [_touchpointer_view getPointerPosition];
|
||||
CGRect viewBounds = [_touchpointer_view bounds];
|
||||
CGRect scrollBounds = [_session_view bounds];
|
||||
|
||||
// add content insets to scroll bounds
|
||||
scrollBounds.size.width += [_session_scrollview contentInset].right;
|
||||
scrollBounds.size.height += [_session_scrollview contentInset].bottom;
|
||||
|
||||
// add zoom factor
|
||||
scrollBounds.size.width *= [_session_scrollview zoomScale];
|
||||
scrollBounds.size.height *= [_session_scrollview zoomScale];
|
||||
|
||||
if (curPointerPos.x > (viewBounds.size.width - [_touchpointer_view getPointerWidth]))
|
||||
scrollX = AUTOSCROLLDISTANCE;
|
||||
else if (curPointerPos.x < 0)
|
||||
scrollX = -AUTOSCROLLDISTANCE;
|
||||
|
||||
if (curPointerPos.y > (viewBounds.size.height - [_touchpointer_view getPointerHeight]))
|
||||
scrollY = AUTOSCROLLDISTANCE;
|
||||
else if (curPointerPos.y < (_session_toolbar_visible ? TOOLBAR_HEIGHT : 0))
|
||||
scrollY = -AUTOSCROLLDISTANCE;
|
||||
|
||||
CGPoint newOffset = [_session_scrollview contentOffset];
|
||||
newOffset.x += scrollX;
|
||||
newOffset.y += scrollY;
|
||||
|
||||
// if offset is going off screen - stop scrolling in that direction
|
||||
if (newOffset.x < 0)
|
||||
{
|
||||
scrollX = 0;
|
||||
newOffset.x = 0;
|
||||
}
|
||||
else if (newOffset.x > (scrollBounds.size.width - viewBounds.size.width))
|
||||
{
|
||||
scrollX = 0;
|
||||
newOffset.x = MAX(scrollBounds.size.width - viewBounds.size.width, 0);
|
||||
}
|
||||
if (newOffset.y < 0)
|
||||
{
|
||||
scrollY = 0;
|
||||
newOffset.y = 0;
|
||||
}
|
||||
else if (newOffset.y > (scrollBounds.size.height - viewBounds.size.height))
|
||||
{
|
||||
scrollY = 0;
|
||||
newOffset.y = MAX(scrollBounds.size.height - viewBounds.size.height, 0);
|
||||
}
|
||||
|
||||
// perform scrolling
|
||||
[_session_scrollview setContentOffset:newOffset];
|
||||
|
||||
// continue scrolling?
|
||||
if (scrollX != 0 || scrollY != 0)
|
||||
[self performSelector:@selector(doAutoScrolling) withObject:nil afterDelay:AUTOSCROLLTIMEOUT];
|
||||
else
|
||||
_is_autoscrolling = NO;
|
||||
}
|
||||
|
||||
// callback for a right click action
|
||||
-(void)touchPointerMove:(CGPoint)pos
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[self handleMouseMoveForPosition:session_view_pos];
|
||||
|
||||
if (_autoscroll_with_touchpointer && !_is_autoscrolling)
|
||||
{
|
||||
_is_autoscrolling = YES;
|
||||
[self performSelector:@selector(doAutoScrolling) withObject:nil afterDelay:AUTOSCROLLTIMEOUT];
|
||||
}
|
||||
}
|
||||
|
||||
// callback if scrolling is performed
|
||||
-(void)touchPointerScrollDown:(BOOL)down
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(down) position:CGPointZero]];
|
||||
}
|
||||
|
||||
// callback for toggling the standard keyboard
|
||||
-(void)touchPointerToggleKeyboard
|
||||
{
|
||||
if(_advanced_keyboard_visible)
|
||||
[self toggleKeyboardWhenOtherVisible:nil];
|
||||
else
|
||||
[self toggleKeyboard:nil];
|
||||
}
|
||||
|
||||
// callback for toggling the extended keyboard
|
||||
-(void)touchPointerToggleExtendedKeyboard
|
||||
{
|
||||
[self toggleExtKeyboard:nil];
|
||||
}
|
||||
|
||||
// callback for reset view
|
||||
-(void)touchPointerResetSessionView
|
||||
{
|
||||
[_session_scrollview setZoomScale:1.0 animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation RDPSessionViewController (Private)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Helper functions
|
||||
|
||||
-(void)showSessionToolbar:(BOOL)show
|
||||
{
|
||||
// already shown or hidden?
|
||||
if (_session_toolbar_visible == show)
|
||||
return;
|
||||
|
||||
if(show)
|
||||
{
|
||||
[UIView beginAnimations:@"showToolbar" context:nil];
|
||||
[UIView setAnimationDuration:.4];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, 0.0, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
[UIView commitAnimations];
|
||||
_session_toolbar_visible = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[UIView beginAnimations:@"hideToolbar" context:nil];
|
||||
[UIView setAnimationDuration:.4];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
[UIView commitAnimations];
|
||||
_session_toolbar_visible = NO;
|
||||
}
|
||||
}
|
||||
|
||||
-(UIToolbar*)keyboardToolbar
|
||||
{
|
||||
UIToolbar* keyboard_toolbar = [[[UIToolbar alloc] initWithFrame:CGRectNull] autorelease];
|
||||
[keyboard_toolbar setBarStyle:UIBarStyleBlackOpaque];
|
||||
|
||||
UIBarButtonItem* esc_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Esc" style:UIBarButtonItemStyleBordered target:self action:@selector(pressEscKey:)] autorelease];
|
||||
UIImage* win_icon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"toolbar_icon_win" ofType:@"png"]];
|
||||
UIBarButtonItem* win_btn = [[[UIBarButtonItem alloc] initWithImage:win_icon style:UIBarButtonItemStyleBordered target:self action:@selector(toggleWinKey:)] autorelease];
|
||||
UIBarButtonItem* ctrl_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Ctrl" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleCtrlKey:)] autorelease];
|
||||
UIBarButtonItem* alt_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Alt" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleAltKey:)] autorelease];
|
||||
UIBarButtonItem* ext_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Ext" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleKeyboardWhenOtherVisible:)] autorelease];
|
||||
UIBarButtonItem* done_btn = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(toggleKeyboard:)] autorelease];
|
||||
UIBarButtonItem* flex_spacer = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
|
||||
|
||||
// iPad gets a shift button, iphone doesn't (there's just not enough space ...)
|
||||
NSArray* items;
|
||||
if(IsPad())
|
||||
{
|
||||
UIBarButtonItem* shift_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Shift" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleShiftKey:)] autorelease];
|
||||
items = [NSArray arrayWithObjects:esc_btn, flex_spacer,
|
||||
shift_btn, flex_spacer,
|
||||
ctrl_btn, flex_spacer,
|
||||
win_btn, flex_spacer,
|
||||
alt_btn, flex_spacer,
|
||||
ext_btn, flex_spacer, done_btn, nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
items = [NSArray arrayWithObjects:esc_btn, flex_spacer, ctrl_btn, flex_spacer, win_btn, flex_spacer, alt_btn, flex_spacer, ext_btn, flex_spacer, done_btn, nil];
|
||||
}
|
||||
|
||||
[keyboard_toolbar setItems:items];
|
||||
[keyboard_toolbar sizeToFit];
|
||||
return keyboard_toolbar;
|
||||
}
|
||||
|
||||
- (void)initGestureRecognizers
|
||||
{
|
||||
// single and double tap recognizer
|
||||
UITapGestureRecognizer* doubleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)] autorelease];
|
||||
[doubleTapRecognizer setNumberOfTouchesRequired:1];
|
||||
[doubleTapRecognizer setNumberOfTapsRequired:2];
|
||||
|
||||
UITapGestureRecognizer* singleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)] autorelease];
|
||||
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
|
||||
[singleTapRecognizer setNumberOfTouchesRequired:1];
|
||||
[singleTapRecognizer setNumberOfTapsRequired:1];
|
||||
|
||||
// 2 fingers - tap recognizer
|
||||
UITapGestureRecognizer* single2FingersTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingle2FingersTap:)] autorelease];
|
||||
[single2FingersTapRecognizer setNumberOfTouchesRequired:2];
|
||||
[single2FingersTapRecognizer setNumberOfTapsRequired:1];
|
||||
|
||||
// long press gesture recognizer
|
||||
UILongPressGestureRecognizer* longPressRecognizer = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)] autorelease];
|
||||
[longPressRecognizer setMinimumPressDuration:0.5];
|
||||
|
||||
// double long press gesture recognizer
|
||||
UILongPressGestureRecognizer* doubleLongPressRecognizer = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleLongPress:)] autorelease];
|
||||
[doubleLongPressRecognizer setNumberOfTouchesRequired:2];
|
||||
[doubleLongPressRecognizer setMinimumPressDuration:0.5];
|
||||
|
||||
// 3 finger, single tap gesture for showing/hiding the toolbar
|
||||
UITapGestureRecognizer* single3FingersTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingle3FingersTap:)] autorelease];
|
||||
[single3FingersTapRecognizer setNumberOfTapsRequired:1];
|
||||
[single3FingersTapRecognizer setNumberOfTouchesRequired:3];
|
||||
|
||||
// add gestures to scroll view
|
||||
[_session_scrollview addGestureRecognizer:singleTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:doubleTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:single2FingersTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:longPressRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:doubleLongPressRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:single3FingersTapRecognizer];
|
||||
}
|
||||
|
||||
- (void)suspendSession
|
||||
{
|
||||
// suspend session and pop navigation controller
|
||||
[_session suspend];
|
||||
|
||||
// pop current view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (NSDictionary*)eventDescriptorForMouseEvent:(int)event position:(CGPoint)position
|
||||
{
|
||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"mouse", @"type",
|
||||
[NSNumber numberWithUnsignedShort:event], @"flags",
|
||||
[NSNumber numberWithUnsignedShort:lrintf(position.x)], @"coord_x",
|
||||
[NSNumber numberWithUnsignedShort:lrintf(position.y)], @"coord_y",
|
||||
nil];
|
||||
}
|
||||
|
||||
- (void)sendDelayedMouseEventWithTimer:(NSTimer*)timer
|
||||
{
|
||||
_mouse_move_event_timer = nil;
|
||||
NSDictionary* event = [timer userInfo];
|
||||
[_session sendInputEvent:event];
|
||||
[timer autorelease];
|
||||
}
|
||||
|
||||
- (void)handleMouseMoveForPosition:(CGPoint)position
|
||||
{
|
||||
NSDictionary* event = [self eventDescriptorForMouseEvent:PTR_FLAGS_MOVE position:position];
|
||||
|
||||
// cancel pending mouse move events
|
||||
[_mouse_move_event_timer invalidate];
|
||||
_mouse_move_events_skipped++;
|
||||
|
||||
if (_mouse_move_events_skipped >= 5)
|
||||
{
|
||||
[_session sendInputEvent:event];
|
||||
_mouse_move_events_skipped = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_mouse_move_event_timer autorelease];
|
||||
_mouse_move_event_timer = [[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(sendDelayedMouseEventWithTimer:) userInfo:event repeats:NO] retain];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
controller for screen settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
@class OrderedDictionary;
|
||||
|
||||
@interface ScreenSelectionController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
NSString* _keyPath;
|
||||
ConnectionParams* _params;
|
||||
|
||||
// avaiable options
|
||||
OrderedDictionary* _color_options;
|
||||
NSArray* _resolution_modes;
|
||||
|
||||
// current selections
|
||||
int _selection_color;
|
||||
int _selection_resolution;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params;
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
|
||||
@end
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
controller for screen settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "Utils.h"
|
||||
#import "OrderedDictionary.h"
|
||||
#import "ConnectionParams.h"
|
||||
|
||||
@interface ScreenSelectionController (Private)
|
||||
-(NSString*)keyPathForKey:(NSString*)key;
|
||||
@end
|
||||
|
||||
@implementation ScreenSelectionController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params
|
||||
{
|
||||
return [self initWithConnectionParams:params keyPath:nil];
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self)
|
||||
{
|
||||
_params = [params retain];
|
||||
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
|
||||
|
||||
_color_options = (OrderedDictionary*)[SelectionForColorSetting() retain];
|
||||
_resolution_modes = [ResolutionModes() retain];
|
||||
|
||||
// init current selections
|
||||
NSUInteger idx = [_color_options indexForValue:[NSNumber numberWithInt:[_params intForKeyPath:[self keyPathForKey:@"colors"]]]];
|
||||
_selection_color = (idx != NSNotFound) ? idx : 0;
|
||||
|
||||
idx = [_resolution_modes indexOfObject:ScreenResolutionDescription([_params intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]],
|
||||
[_params intForKeyPath:[self keyPathForKey:@"width"]],
|
||||
[_params intForKeyPath:[self keyPathForKey:@"height"]])];
|
||||
_selection_resolution = (idx != NSNotFound) ? idx : 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[_params autorelease];
|
||||
[_keyPath autorelease];
|
||||
[_color_options autorelease];
|
||||
[_resolution_modes autorelease];
|
||||
}
|
||||
|
||||
-(NSString*)keyPathForKey:(NSString*)key
|
||||
{
|
||||
if (_keyPath)
|
||||
return [_keyPath stringByAppendingFormat:@".%@", key];
|
||||
return key;
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
// Return the number of rows in the section.
|
||||
if (section == 0)
|
||||
return [_color_options count];
|
||||
return [_resolution_modes count] + 2; // +2 for custom width/height input fields
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = nil;
|
||||
switch ([indexPath section])
|
||||
{
|
||||
case 0:
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
[[cell textLabel] setText:[_color_options keyAtIndex:[indexPath row]]];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if ([indexPath row] < [_resolution_modes count])
|
||||
{
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
[[cell textLabel] setText:[_resolution_modes objectAtIndex:[indexPath row]]];
|
||||
}
|
||||
else
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierText];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ([indexPath section] == 1)
|
||||
{
|
||||
BOOL enabled = ([_params intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]] == TSXScreenOptionCustom);
|
||||
if ([indexPath row] == [_resolution_modes count])
|
||||
{
|
||||
int value = [_params intForKeyPath:[self keyPathForKey:@"width"]];
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Width", @"Custom Screen Width")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 800]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
[[textCell label] setEnabled:enabled];
|
||||
[[textCell textfield] setEnabled:enabled];
|
||||
[[textCell textfield] setTag:1];
|
||||
}
|
||||
else if ([indexPath row] == ([_resolution_modes count] + 1))
|
||||
{
|
||||
int value = [_params intForKeyPath:[self keyPathForKey:@"height"]];
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Height", @"Custom Screen Height")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 600]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
[[textCell label] setEnabled:enabled];
|
||||
[[textCell textfield] setEnabled:enabled];
|
||||
[[textCell textfield] setTag:2];
|
||||
}
|
||||
}
|
||||
|
||||
// set default checkmark
|
||||
if([indexPath row] == ([indexPath section] == 0 ? _selection_color : _selection_resolution))
|
||||
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
|
||||
else
|
||||
[cell setAccessoryType:UITableViewCellAccessoryNone];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// custom widht/height cells are not selectable
|
||||
if ([indexPath section] == 1 && [indexPath row] >= [_resolution_modes count])
|
||||
return;
|
||||
|
||||
// has selection change?
|
||||
int cur_selection = ([indexPath section] == 0 ? _selection_color : _selection_resolution);
|
||||
if([indexPath row] != cur_selection)
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSIndexPath* oldIndexPath = [NSIndexPath indexPathForRow:cur_selection inSection:[indexPath section]];
|
||||
|
||||
// clear old checkmark
|
||||
UITableViewCell* old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
|
||||
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
|
||||
// set new checkmark
|
||||
UITableViewCell* new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
|
||||
if ([indexPath section] == 0)
|
||||
{
|
||||
// get value from color dictionary
|
||||
int sel_value = [[_color_options valueForKey:[_color_options keyAtIndex:[indexPath row]]] intValue];
|
||||
|
||||
// update selection index and params value
|
||||
[_params setInt:sel_value forKeyPath:[self keyPathForKey:@"colors"]];
|
||||
_selection_color = [indexPath row];
|
||||
}
|
||||
else
|
||||
{
|
||||
// update selection index and params value
|
||||
int width, height;
|
||||
TSXScreenOptions mode;
|
||||
ScanScreenResolution([_resolution_modes objectAtIndex:[indexPath row]], &width, &height, &mode);
|
||||
[_params setInt:mode forKeyPath:[self keyPathForKey:@"screen_resolution_type"]];
|
||||
if (mode != TSXScreenOptionCustom)
|
||||
{
|
||||
[_params setInt:width forKeyPath:[self keyPathForKey:@"width"]];
|
||||
[_params setInt:height forKeyPath:[self keyPathForKey:@"height"]];
|
||||
}
|
||||
_selection_resolution = [indexPath row];
|
||||
|
||||
// refresh width/height edit fields if custom selection changed
|
||||
NSArray* indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:[_resolution_modes count] inSection:1],
|
||||
[NSIndexPath indexPathForRow:([_resolution_modes count] + 1) inSection:1], nil];
|
||||
[[self tableView] reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
|
||||
switch([textField tag])
|
||||
{
|
||||
// update resolution settings (and check for invalid input)
|
||||
case 1:
|
||||
if ([[textField text] intValue] < 640) [textField setText:@"640"];
|
||||
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"width"]];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ([[textField text] intValue] < 480) [textField setText:@"480"];
|
||||
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"height"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Certificate verification controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RDPSession;
|
||||
|
||||
@interface VerifyCertificateController : UIViewController
|
||||
{
|
||||
@private
|
||||
IBOutlet UILabel* _label_issuer;
|
||||
IBOutlet UIButton* _btn_accept;
|
||||
IBOutlet UIButton* _btn_decline;
|
||||
IBOutlet UILabel* _label_message;
|
||||
IBOutlet UILabel* _label_for_issuer;
|
||||
|
||||
RDPSession* _session;
|
||||
NSMutableDictionary* _params;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session params:(NSMutableDictionary*)params;
|
||||
|
||||
@end
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Certificate verification controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "VerifyCertificateController.h"
|
||||
#import "RDPSession.h"
|
||||
|
||||
@implementation VerifyCertificateController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session params:(NSMutableDictionary *)params
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
_session = session;
|
||||
_params = params;
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString* message = NSLocalizedString(@"The identity of the remote computer cannot be verified. Do you want to connect anyway?", @"Verify certificate view message");
|
||||
|
||||
// init strings
|
||||
[_label_message setText:message];
|
||||
[_label_for_issuer setText:NSLocalizedString(@"Issuer:", @"Verify certificate view issuer label")];
|
||||
[_btn_accept setTitle:NSLocalizedString(@"Yes", @"Yes Button") forState:UIControlStateNormal];
|
||||
[_btn_decline setTitle:NSLocalizedString(@"No", @"No Button") forState:UIControlStateNormal];
|
||||
|
||||
[_label_issuer setText:[_params valueForKey:@"issuer"]];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
// set signal
|
||||
[[_session uiRequestCompleted] signal];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (IBAction)acceptPressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)declinePressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>TSXDefaultComputerBookmarkSettings</key>
|
||||
<dict>
|
||||
<key>hostname</key>
|
||||
<string></string>
|
||||
<key>port</key>
|
||||
<integer>3389</integer>
|
||||
<key>screen_resolution_type</key>
|
||||
<integer>0</integer>
|
||||
<key>width</key>
|
||||
<integer>1024</integer>
|
||||
<key>height</key>
|
||||
<integer>768</integer>
|
||||
<key>colors</key>
|
||||
<integer>16</integer>
|
||||
<key>perf_font_smoothing</key>
|
||||
<false/>
|
||||
<key>perf_menu_animation</key>
|
||||
<false/>
|
||||
<key>perf_show_desktop</key>
|
||||
<false/>
|
||||
<key>perf_window_dragging</key>
|
||||
<false/>
|
||||
<key>perf_windows_themes</key>
|
||||
<false/>
|
||||
<key>perf_remotefx</key>
|
||||
<false/>
|
||||
<key>perf_desktop_composition</key>
|
||||
<false/>
|
||||
<key>enable_3g_settings</key>
|
||||
<false/>
|
||||
<key>settings_3g</key>
|
||||
<dict>
|
||||
<key>screen_resolution_type</key>
|
||||
<integer>0</integer>
|
||||
<key>width</key>
|
||||
<integer>800</integer>
|
||||
<key>height</key>
|
||||
<integer>600</integer>
|
||||
<key>colors</key>
|
||||
<integer>16</integer>
|
||||
<key>perf_remotefx</key>
|
||||
<false/>
|
||||
<key>perf_desktop_composition</key>
|
||||
<false/>
|
||||
<key>perf_windows_themes</key>
|
||||
<false/>
|
||||
<key>perf_window_dragging</key>
|
||||
<false/>
|
||||
<key>perf_show_desktop</key>
|
||||
<false/>
|
||||
<key>perf_menu_animation</key>
|
||||
<false/>
|
||||
<key>perf_font_smoothing</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>security</key>
|
||||
<integer>0</integer>
|
||||
<key>remote_program</key>
|
||||
<string></string>
|
||||
<key>working_dir</key>
|
||||
<string></string>
|
||||
<key>console</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>ui.auto_scroll_touchpointer</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
RDP run-loop
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <freerdp/freerdp.h>
|
||||
#import <freerdp/channels/channels.h>
|
||||
#import "TSXTypes.h"
|
||||
|
||||
@class RDPSession, RDPSessionView;
|
||||
|
||||
// FreeRDP extended structs
|
||||
typedef struct mf_info mfInfo;
|
||||
|
||||
|
||||
typedef struct mf_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
mfInfo* mfi;
|
||||
rdpSettings* settings;
|
||||
} mfContext;
|
||||
|
||||
|
||||
struct mf_info
|
||||
{
|
||||
// RDP
|
||||
freerdp* instance;
|
||||
mfContext* context;
|
||||
rdpContext* _context;
|
||||
|
||||
// UI
|
||||
RDPSession* session;
|
||||
|
||||
// Graphics
|
||||
CGContextRef bitmap_context;
|
||||
|
||||
// Events
|
||||
int event_pipe_producer, event_pipe_consumer;
|
||||
|
||||
// Tracking connection state
|
||||
volatile TSXConnectionState connection_state;
|
||||
volatile BOOL unwanted; // set when controlling Session no longer wants the connection to continue
|
||||
};
|
||||
|
||||
|
||||
#define MFI_FROM_INSTANCE(inst) (((mfContext*)((inst)->context))->mfi)
|
||||
|
||||
|
||||
enum MF_EXIT_CODE
|
||||
{
|
||||
MF_EXIT_SUCCESS = 0,
|
||||
|
||||
MF_EXIT_CONN_FAILED = 128,
|
||||
MF_EXIT_CONN_CANCELED = 129,
|
||||
MF_EXIT_LOGON_TIMEOUT = 130,
|
||||
|
||||
MF_EXIT_UNKNOWN = 255
|
||||
};
|
||||
|
||||
void ios_init_freerdp(void);
|
||||
void ios_uninit_freerdp(void);
|
||||
freerdp* ios_freerdp_new(void);
|
||||
int ios_run_freerdp(freerdp* instance);
|
||||
void ios_freerdp_free(freerdp* instance);
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
RDP run-loop
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <freerdp/utils/event.h>
|
||||
#import <freerdp/gdi/gdi.h>
|
||||
#import <freerdp/utils/file.h>
|
||||
|
||||
#import "ios_freerdp.h"
|
||||
#import "ios_freerdp_ui.h"
|
||||
#import "ios_freerdp_events.h"
|
||||
|
||||
#import "RDPSession.h"
|
||||
#import "Utils.h"
|
||||
|
||||
|
||||
#pragma mark Connection helpers
|
||||
|
||||
static BOOL
|
||||
ios_pre_connect(freerdp * instance)
|
||||
{
|
||||
rdpSettings* settings = instance->settings;
|
||||
|
||||
settings->AutoLogonEnabled = settings->Password && (strlen(settings->Password) > 0);
|
||||
|
||||
// Verify screen width/height are sane
|
||||
if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) || (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
|
||||
{
|
||||
NSLog(@"%s: invalid dimensions %d %d", __func__, settings->DesktopWidth, settings->DesktopHeight);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL bitmap_cache = settings->BitmapCacheEnabled;
|
||||
|
||||
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache;
|
||||
settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
|
||||
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
|
||||
settings->FrameAcknowledge = 10;
|
||||
|
||||
// freerdp_channels_pre_connect(instance->context->channels, instance);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ios_post_connect(freerdp* instance)
|
||||
{
|
||||
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
|
||||
|
||||
instance->context->cache = cache_new(instance->settings);
|
||||
|
||||
// Graphics callbacks
|
||||
ios_allocate_display_buffer(mfi);
|
||||
instance->update->BeginPaint = ios_ui_begin_paint;
|
||||
instance->update->EndPaint = ios_ui_end_paint;
|
||||
instance->update->DesktopResize = ios_ui_resize_window;
|
||||
|
||||
// Channel allocation
|
||||
// freerdp_channels_post_connect(instance->context->channels, instance);
|
||||
|
||||
[mfi->session performSelectorOnMainThread:@selector(sessionDidConnect) withObject:nil waitUntilDone:YES];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Running the connection
|
||||
|
||||
int
|
||||
ios_run_freerdp(freerdp * instance)
|
||||
{
|
||||
mfContext* context = (mfContext*)instance->context;
|
||||
mfInfo* mfi = context->mfi;
|
||||
// rdpChannels* channels = instance->context->channels;
|
||||
|
||||
mfi->connection_state = TSXConnectionConnecting;
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
{
|
||||
NSLog(@"%s: inst->rdp_connect failed", __func__);
|
||||
return mfi->unwanted ? MF_EXIT_CONN_CANCELED : MF_EXIT_CONN_FAILED;
|
||||
}
|
||||
|
||||
if (mfi->unwanted)
|
||||
return MF_EXIT_CONN_CANCELED;
|
||||
|
||||
mfi->connection_state = TSXConnectionConnected;
|
||||
|
||||
// Connection main loop
|
||||
NSAutoreleasePool* pool;
|
||||
int i;
|
||||
int fds;
|
||||
int max_fds;
|
||||
int rcount;
|
||||
int wcount;
|
||||
void* rfds[32];
|
||||
void* wfds[32];
|
||||
fd_set rfds_set;
|
||||
fd_set wfds_set;
|
||||
|
||||
memset(rfds, 0, sizeof(rfds));
|
||||
memset(wfds, 0, sizeof(wfds));
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = wcount = 0;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
{
|
||||
NSLog(@"%s: inst->rdp_get_fds failed", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
{
|
||||
NSLog(@"%s: freerdp_chanman_get_fds failed", __func__);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (ios_events_get_fds(mfi, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
{
|
||||
NSLog(@"%s: ios_events_get_fds", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
FD_ZERO(&wfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
|
||||
{
|
||||
/* these are not really errors */
|
||||
if (!((errno == EAGAIN) ||
|
||||
(errno == EWOULDBLOCK) ||
|
||||
(errno == EINPROGRESS) ||
|
||||
(errno == EINTR))) /* signal occurred */
|
||||
{
|
||||
NSLog(@"%s: max_sck is zero.", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the libfreerdp fds
|
||||
if (freerdp_check_fds(instance) != true)
|
||||
{
|
||||
NSLog(@"%s: inst->rdp_check_fds failed.", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check input event fds
|
||||
if (ios_events_check_fds(mfi, &rfds_set) != TRUE)
|
||||
{
|
||||
// This event will fail when the app asks for a disconnect.
|
||||
//NSLog(@"%s: ios_events_check_fds failed: terminating connection.", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check channel fds
|
||||
/* if (freerdp_channels_check_fds(channels, instance) != TRUE)
|
||||
{
|
||||
NSLog(@"%s: freerdp_chanman_check_fds failed", __func__);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
[pool release]; pool = nil;
|
||||
}
|
||||
|
||||
mfi->connection_state = TSXConnectionDisconnected;
|
||||
|
||||
// Cleanup
|
||||
// freerdp_channels_close(channels, instance);
|
||||
// freerdp_channels_free(channels);
|
||||
freerdp_disconnect(instance);
|
||||
gdi_free(instance);
|
||||
cache_free(instance->context->cache);
|
||||
|
||||
[pool release]; pool = nil;
|
||||
return MF_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Context callbacks
|
||||
|
||||
void ios_context_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
mfInfo* mfi = (mfInfo*)calloc(1, sizeof(mfInfo));
|
||||
((mfContext*) context)->mfi = mfi;
|
||||
// context->channels = freerdp_channels_new();
|
||||
ios_events_create_pipe(mfi);
|
||||
|
||||
mfi->_context = context;
|
||||
mfi->context = (mfContext*)context;
|
||||
mfi->context->settings = instance->settings;
|
||||
mfi->instance = instance;
|
||||
}
|
||||
|
||||
void ios_context_free(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
mfInfo* mfi = ((mfContext*) context)->mfi;
|
||||
ios_events_free_pipe(mfi);
|
||||
free(mfi);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and cleanup
|
||||
|
||||
freerdp* ios_freerdp_new()
|
||||
{
|
||||
freerdp* inst = freerdp_new();
|
||||
|
||||
inst->PreConnect = ios_pre_connect;
|
||||
inst->PostConnect = ios_post_connect;
|
||||
inst->Authenticate = ios_ui_authenticate;
|
||||
inst->VerifyCertificate = ios_ui_check_certificate;
|
||||
inst->VerifyChangedCertificate = ios_ui_check_changed_certificate;
|
||||
|
||||
inst->context_size = sizeof(mfContext);
|
||||
inst->ContextNew = ios_context_new;
|
||||
inst->ContextFree = ios_context_free;
|
||||
freerdp_context_new(inst);
|
||||
|
||||
// determine new home path
|
||||
NSString* home_path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
|
||||
free(inst->settings->HomePath);
|
||||
free(inst->settings->ConfigPath);
|
||||
inst->settings->HomePath = strdup([home_path UTF8String]);
|
||||
inst->settings->ConfigPath = NULL;
|
||||
freerdp_detect_paths(inst->settings);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
void ios_freerdp_free(freerdp* instance)
|
||||
{
|
||||
freerdp_context_free(instance);
|
||||
freerdp_free(instance);
|
||||
}
|
||||
|
||||
void ios_init_freerdp()
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
// freerdp_channels_global_init();
|
||||
}
|
||||
|
||||
void ios_uninit_freerdp()
|
||||
{
|
||||
// freerdp_channels_global_uninit();
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
RDP event queuing
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef IOS_RDP_EVENT_H
|
||||
#define IOS_RDP_EVENT_H
|
||||
|
||||
#import "ios_freerdp.h"
|
||||
|
||||
// For UI: use to send events
|
||||
BOOL ios_events_send(mfInfo* mfi, NSDictionary * event_description);
|
||||
|
||||
// For connection runloop: use to poll for queued input events
|
||||
BOOL ios_events_get_fds(mfInfo* mfi, void ** read_fds, int * read_count, void ** write_fds, int * write_count);
|
||||
BOOL ios_events_check_fds(mfInfo* mfi, fd_set* rfds);
|
||||
BOOL ios_events_create_pipe(mfInfo* mfi);
|
||||
void ios_events_free_pipe(mfInfo* mfi);
|
||||
|
||||
#endif /* IOS_RDP_EVENT_H */
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
RDP event queuing
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "ios_freerdp_events.h"
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Sending compacted input events (from main thread)
|
||||
|
||||
// While this function may be called from any thread that has an autorelease pool allocated, it is not threadsafe: caller is responsible for synchronization
|
||||
BOOL ios_events_send(mfInfo* mfi, NSDictionary * event_description)
|
||||
{
|
||||
NSData * encoded_description = [NSKeyedArchiver archivedDataWithRootObject:event_description];
|
||||
|
||||
if ([encoded_description length] > 32000 || (mfi->event_pipe_producer == -1) )
|
||||
return FALSE;
|
||||
|
||||
uint32_t archived_data_len = (uint32_t)[encoded_description length];
|
||||
|
||||
//NSLog(@"writing %d bytes to input event pipe", archived_data_len);
|
||||
|
||||
if (write(mfi->event_pipe_producer, &archived_data_len, 4) == -1)
|
||||
{
|
||||
NSLog(@"%s: Failed to write length descriptor to pipe.", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (write(mfi->event_pipe_producer, [encoded_description bytes], archived_data_len) == -1)
|
||||
{
|
||||
NSLog(@"%s: Failed to write %d bytes into the event queue (event type: %@).", __func__, (int)[encoded_description length], [event_description objectForKey:@"type"]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Processing compacted input events (from connection thread runloop)
|
||||
|
||||
static BOOL ios_events_handle_event(mfInfo* mfi, NSDictionary * event_description)
|
||||
{
|
||||
NSString * event_type = [event_description objectForKey:@"type"];
|
||||
BOOL should_continue = TRUE;
|
||||
freerdp* instance = mfi->instance;
|
||||
|
||||
if ([event_type isEqualToString:@"mouse"])
|
||||
{
|
||||
instance->input->MouseEvent(instance->input,
|
||||
[[event_description objectForKey:@"flags"] unsignedShortValue],
|
||||
[[event_description objectForKey:@"coord_x"] unsignedShortValue],
|
||||
[[event_description objectForKey:@"coord_y"] unsignedShortValue]);
|
||||
}
|
||||
else if ([event_type isEqualToString:@"keyboard"])
|
||||
{
|
||||
if ([[event_description objectForKey:@"subtype"] isEqualToString:@"scancode"])
|
||||
instance->input->KeyboardEvent(instance->input,
|
||||
[[event_description objectForKey:@"flags"] unsignedShortValue],
|
||||
[[event_description objectForKey:@"scancode"] unsignedShortValue]);
|
||||
else if ([[event_description objectForKey:@"subtype"] isEqualToString:@"unicode"])
|
||||
instance->input->UnicodeKeyboardEvent(instance->input,
|
||||
[[event_description objectForKey:@"flags"] unsignedShortValue],
|
||||
[[event_description objectForKey:@"unicode_char"] unsignedShortValue]);
|
||||
else
|
||||
NSLog(@"%s: doesn't know how to send keyboard input with subtype %@", __func__, [event_description objectForKey:@"subtype"]);
|
||||
}
|
||||
else if ([event_type isEqualToString:@"disconnect"])
|
||||
should_continue = FALSE;
|
||||
else
|
||||
NSLog(@"%s: unrecognized event type: %@", __func__, event_type);
|
||||
|
||||
return should_continue;
|
||||
}
|
||||
|
||||
BOOL ios_events_check_fds(mfInfo* mfi, fd_set* rfds)
|
||||
{
|
||||
if ( (mfi->event_pipe_consumer == -1) || !FD_ISSET(mfi->event_pipe_consumer, rfds))
|
||||
return TRUE;
|
||||
|
||||
uint32_t archived_data_length = 0;
|
||||
ssize_t bytes_read;
|
||||
|
||||
// First, read the length of the blob
|
||||
bytes_read = read(mfi->event_pipe_consumer, &archived_data_length, 4);
|
||||
|
||||
if (bytes_read == -1 || archived_data_length < 1 || archived_data_length > 32000)
|
||||
{
|
||||
NSLog(@"%s: just read length descriptor. bytes_read=%ld, archived_data_length=%u", __func__, bytes_read, archived_data_length);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//NSLog(@"reading %d bytes from input event pipe", archived_data_length);
|
||||
|
||||
NSMutableData * archived_object_data = [[NSMutableData alloc] initWithLength:archived_data_length];
|
||||
bytes_read = read(mfi->event_pipe_consumer, [archived_object_data mutableBytes], archived_data_length);
|
||||
|
||||
if (bytes_read != archived_data_length)
|
||||
{
|
||||
NSLog(@"%s: attempted to read data; read %ld bytes but wanted %d bytes.", __func__, bytes_read, archived_data_length);
|
||||
[archived_object_data release];
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
id unarchived_object_data = [NSKeyedUnarchiver unarchiveObjectWithData:archived_object_data];
|
||||
[archived_object_data release];
|
||||
|
||||
return ios_events_handle_event(mfi, unarchived_object_data);
|
||||
}
|
||||
|
||||
BOOL ios_events_get_fds(mfInfo* mfi, void ** read_fds, int * read_count, void ** write_fds, int * write_count)
|
||||
{
|
||||
read_fds[*read_count] = (void *)(long)(mfi->event_pipe_consumer);
|
||||
(*read_count)++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Sets up the event pipe
|
||||
BOOL ios_events_create_pipe(mfInfo* mfi)
|
||||
{
|
||||
int pipe_fds[2];
|
||||
|
||||
if (pipe(pipe_fds) == -1)
|
||||
{
|
||||
NSLog(@"%s: pipe failed.", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mfi->event_pipe_consumer = pipe_fds[0];
|
||||
mfi->event_pipe_producer = pipe_fds[1];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ios_events_free_pipe(mfInfo* mfi)
|
||||
{
|
||||
int consumer_fd = mfi->event_pipe_consumer, producer_fd = mfi->event_pipe_producer;
|
||||
|
||||
mfi->event_pipe_consumer = mfi->event_pipe_producer = -1;
|
||||
close(producer_fd);
|
||||
close(consumer_fd);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
RDP ui callbacks
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "ios_freerdp.h"
|
||||
|
||||
void ios_ui_begin_paint(rdpContext * context);
|
||||
void ios_ui_end_paint(rdpContext * context);
|
||||
void ios_ui_resize_window(rdpContext * context);
|
||||
|
||||
BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, char** domain);
|
||||
BOOL ios_ui_check_certificate(freerdp * instance, char * subject, char * issuer, char * fingerprint);
|
||||
BOOL ios_ui_check_changed_certificate(freerdp * instance, char * subject, char * issuer, char * new_fingerprint, char * old_fingerprint);
|
||||
|
||||
void ios_allocate_display_buffer(mfInfo* mfi);
|
||||
void ios_resize_display_buffer(mfInfo* mfi);
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
RDP ui callbacks
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <freerdp/gdi/gdi.h>
|
||||
#import "ios_freerdp_ui.h"
|
||||
|
||||
#import "RDPSession.h"
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Certificate authentication
|
||||
|
||||
BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, char** domain)
|
||||
{
|
||||
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
|
||||
|
||||
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
(*username) ? [NSString stringWithUTF8String:*username] : @"", @"username",
|
||||
(*password) ? [NSString stringWithUTF8String:*password] : @"", @"password",
|
||||
(*domain) ? [NSString stringWithUTF8String:*domain] : @"", @"domain",
|
||||
[NSString stringWithUTF8String:instance->settings->ServerHostname], @"hostname", // used for the auth prompt message; not changed
|
||||
nil];
|
||||
|
||||
// request auth UI
|
||||
[mfi->session performSelectorOnMainThread:@selector(sessionRequestsAuthenticationWithParams:) withObject:params waitUntilDone:YES];
|
||||
|
||||
// wait for UI request to be completed
|
||||
[[mfi->session uiRequestCompleted] lock];
|
||||
[[mfi->session uiRequestCompleted] wait];
|
||||
[[mfi->session uiRequestCompleted] unlock];
|
||||
|
||||
if (![[params valueForKey:@"result"] boolValue])
|
||||
{
|
||||
mfi->unwanted = YES;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Free old values
|
||||
free(*username);
|
||||
free(*password);
|
||||
free(*domain);
|
||||
|
||||
// set values back
|
||||
*username = strdup([[params objectForKey:@"username"] UTF8String]);
|
||||
*password = strdup([[params objectForKey:@"password"] UTF8String]);
|
||||
*domain = strdup([[params objectForKey:@"domain"] UTF8String]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ios_ui_check_certificate(freerdp * instance, char * subject, char * issuer, char * fingerprint)
|
||||
{
|
||||
// check whether we accept all certificates
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES)
|
||||
return TRUE;
|
||||
|
||||
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
|
||||
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
(subject) ? [NSString stringWithUTF8String:subject] : @"", @"subject",
|
||||
(issuer) ? [NSString stringWithUTF8String:issuer] : @"", @"issuer",
|
||||
(fingerprint) ? [NSString stringWithUTF8String:subject] : @"", @"fingerprint",
|
||||
nil];
|
||||
|
||||
// request certificate verification UI
|
||||
[mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:) withObject:params waitUntilDone:YES];
|
||||
|
||||
// wait for UI request to be completed
|
||||
[[mfi->session uiRequestCompleted] lock];
|
||||
[[mfi->session uiRequestCompleted] wait];
|
||||
[[mfi->session uiRequestCompleted] unlock];
|
||||
|
||||
if (![[params valueForKey:@"result"] boolValue])
|
||||
{
|
||||
mfi->unwanted = YES;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ios_ui_check_changed_certificate(freerdp * instance, char * subject, char * issuer, char * new_fingerprint, char * old_fingerprint)
|
||||
{
|
||||
return ios_ui_check_certificate(instance, subject, issuer, new_fingerprint);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Graphics updates
|
||||
|
||||
void ios_ui_begin_paint(rdpContext * context)
|
||||
{
|
||||
rdpGdi *gdi = context->gdi;
|
||||
gdi->primary->hdc->hwnd->invalid->null = 1;
|
||||
}
|
||||
|
||||
void ios_ui_end_paint(rdpContext * context)
|
||||
{
|
||||
mfInfo* mfi = MFI_FROM_INSTANCE(context->instance);
|
||||
rdpGdi *gdi = context->gdi;
|
||||
CGRect dirty_rect = CGRectMake(gdi->primary->hdc->hwnd->invalid->x, gdi->primary->hdc->hwnd->invalid->y, gdi->primary->hdc->hwnd->invalid->w, gdi->primary->hdc->hwnd->invalid->h);
|
||||
|
||||
[mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:) withObject:[NSValue valueWithCGRect:dirty_rect] waitUntilDone:NO];
|
||||
}
|
||||
|
||||
|
||||
void ios_ui_resize_window(rdpContext * context)
|
||||
{
|
||||
ios_resize_display_buffer(MFI_FROM_INSTANCE(context->instance));
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Exported
|
||||
|
||||
static void ios_create_bitmap_context(mfInfo* mfi)
|
||||
{
|
||||
[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextWillChange) withObject:nil waitUntilDone:YES];
|
||||
|
||||
rdpGdi* gdi = mfi->instance->context->gdi;
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
if(gdi->dstBpp == 16)
|
||||
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->width * 2, colorSpace, kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
|
||||
else
|
||||
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextDidChange) withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
|
||||
void ios_allocate_display_buffer(mfInfo* mfi)
|
||||
{
|
||||
gdi_init(mfi->instance, CLRCONV_RGB555 | ((mfi->instance->settings->ColorDepth > 16) ? CLRBUF_32BPP : CLRBUF_16BPP), NULL);
|
||||
ios_create_bitmap_context(mfi);
|
||||
}
|
||||
|
||||
void ios_resize_display_buffer(mfInfo* mfi)
|
||||
{
|
||||
// Release the old context in a thread-safe manner
|
||||
CGContextRef old_context = mfi->bitmap_context;
|
||||
mfi->bitmap_context = NULL;
|
||||
CGContextRelease(old_context);
|
||||
|
||||
// Create the new context
|
||||
gdi_resize(mfi->instance->context->gdi, mfi->instance->settings->DesktopWidth, mfi->instance->settings->DesktopHeight);
|
||||
ios_create_bitmap_context(mfi);
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
|
||||
File: Reachability.h
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.2
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2010 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <netinet/in.h>
|
||||
|
||||
typedef enum {
|
||||
NotReachable = 0,
|
||||
ReachableViaWiFi = 1,
|
||||
ReachableViaWWAN = 2
|
||||
} NetworkStatus;
|
||||
#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification"
|
||||
|
||||
@interface Reachability: NSObject
|
||||
{
|
||||
BOOL localWiFiRef;
|
||||
SCNetworkReachabilityRef reachabilityRef;
|
||||
}
|
||||
|
||||
//reachabilityWithHostName- Use to check the reachability of a particular host name.
|
||||
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
|
||||
|
||||
//reachabilityWithAddress- Use to check the reachability of a particular IP address.
|
||||
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
|
||||
|
||||
//reachabilityForInternetConnection- checks whether the default route is available.
|
||||
// Should be used by applications that do not connect to a particular host
|
||||
+ (Reachability*) reachabilityForInternetConnection;
|
||||
|
||||
//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
|
||||
+ (Reachability*) reachabilityForLocalWiFi;
|
||||
|
||||
//Start listening for reachability notifications on the current run loop
|
||||
- (BOOL) startNotifier;
|
||||
- (void) stopNotifier;
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus;
|
||||
//WWAN may be available, but not active until a connection has been established.
|
||||
//WiFi may require a connection for VPN on Demand.
|
||||
- (BOOL) connectionRequired;
|
||||
@end
|
||||
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
|
||||
File: Reachability.m
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.2
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2010 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#import <sys/socket.h>
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import "Reachability.h"
|
||||
|
||||
#define kShouldPrintReachabilityFlags 1
|
||||
|
||||
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
|
||||
{
|
||||
#if kShouldPrintReachabilityFlags
|
||||
|
||||
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
|
||||
comment
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@implementation Reachability
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
|
||||
{
|
||||
#pragma unused (target, flags)
|
||||
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
||||
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
|
||||
|
||||
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
|
||||
// in case someon uses the Reachablity object in a different thread.
|
||||
NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
Reachability* noteObject = (Reachability*) info;
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
|
||||
|
||||
[myPool release];
|
||||
}
|
||||
|
||||
- (BOOL) startNotifier
|
||||
{
|
||||
BOOL retVal = NO;
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
|
||||
{
|
||||
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
|
||||
{
|
||||
retVal = YES;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
- (void) stopNotifier
|
||||
{
|
||||
if(reachabilityRef!= NULL)
|
||||
{
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self stopNotifier];
|
||||
if(reachabilityRef!= NULL)
|
||||
{
|
||||
CFRelease(reachabilityRef);
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
|
||||
{
|
||||
Reachability* retVal = NULL;
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
if(reachability!= NULL)
|
||||
{
|
||||
retVal= [[[self alloc] init] autorelease];
|
||||
if(retVal!= NULL)
|
||||
{
|
||||
retVal->reachabilityRef = reachability;
|
||||
retVal->localWiFiRef = NO;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
|
||||
{
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
|
||||
Reachability* retVal = NULL;
|
||||
if(reachability!= NULL)
|
||||
{
|
||||
retVal= [[[self alloc] init] autorelease];
|
||||
if(retVal!= NULL)
|
||||
{
|
||||
retVal->reachabilityRef = reachability;
|
||||
retVal->localWiFiRef = NO;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
+ (Reachability*) reachabilityForInternetConnection;
|
||||
{
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
return [self reachabilityWithAddress: &zeroAddress];
|
||||
}
|
||||
|
||||
+ (Reachability*) reachabilityForLocalWiFi;
|
||||
{
|
||||
struct sockaddr_in localWifiAddress;
|
||||
bzero(&localWifiAddress, sizeof(localWifiAddress));
|
||||
localWifiAddress.sin_len = sizeof(localWifiAddress);
|
||||
localWifiAddress.sin_family = AF_INET;
|
||||
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
|
||||
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
|
||||
if(retVal!= NULL)
|
||||
{
|
||||
retVal->localWiFiRef = YES;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#pragma mark Network Flag Handling
|
||||
|
||||
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
|
||||
{
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
PrintReachabilityFlags(flags, "networkStatusForFlags");
|
||||
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
|
||||
{
|
||||
// if target host is not reachable
|
||||
return NotReachable;
|
||||
}
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
|
||||
{
|
||||
// if target host is reachable and no connection is required
|
||||
// then we'll assume (for now) that your on Wi-Fi
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
|
||||
|
||||
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
|
||||
{
|
||||
// ... and the connection is on-demand (or on-traffic) if the
|
||||
// calling application is using the CFSocketStream or higher APIs
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
|
||||
{
|
||||
// ... and no [user] intervention is needed
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
retVal = ReachableViaWWAN;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
- (BOOL) connectionRequired;
|
||||
{
|
||||
NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus
|
||||
{
|
||||
NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
|
||||
NetworkStatus retVal = NotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
if(localWiFiRef)
|
||||
{
|
||||
retVal = [self localWiFiStatusForFlags: flags];
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = [self networkStatusForFlags: flags];
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// SFHFKeychainUtils.h
|
||||
//
|
||||
// Created by Buzz Andersen on 10/20/08.
|
||||
// Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone.
|
||||
// Copyright 2008 Sci-Fi Hi-Fi. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface SFHFKeychainUtils : NSObject {
|
||||
|
||||
}
|
||||
|
||||
+ (NSString *) getPasswordForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error;
|
||||
+ (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServerName: (NSString *) serverName updateExisting: (BOOL) updateExisting error: (NSError **) error;
|
||||
+ (BOOL) deleteItemForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error;
|
||||
|
||||
@end
|
|
@ -0,0 +1,434 @@
|
|||
//
|
||||
// SFHFKeychainUtils.m
|
||||
//
|
||||
// Created by Buzz Andersen on 10/20/08.
|
||||
// Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone.
|
||||
// Copyright 2008 Sci-Fi Hi-Fi. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "SFHFKeychainUtils.h"
|
||||
#import <Security/Security.h>
|
||||
|
||||
static NSString *SFHFKeychainUtilsErrorDomain = @"SFHFKeychainUtilsErrorDomain";
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
|
||||
@interface SFHFKeychainUtils (PrivateMethods)
|
||||
+ (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error;
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation SFHFKeychainUtils
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
|
||||
|
||||
+ (NSString *) getPasswordForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error {
|
||||
if (!username || !serviceName) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServerName: serverName error: error];
|
||||
|
||||
if (*error || !item) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// from Advanced Mac OS X Programming, ch. 16
|
||||
UInt32 length;
|
||||
char *password;
|
||||
SecKeychainAttribute attributes[8];
|
||||
SecKeychainAttributeList list;
|
||||
|
||||
attributes[0].tag = kSecAccountItemAttr;
|
||||
attributes[1].tag = kSecDescriptionItemAttr;
|
||||
attributes[2].tag = kSecLabelItemAttr;
|
||||
attributes[3].tag = kSecModDateItemAttr;
|
||||
|
||||
list.count = 4;
|
||||
list.attr = attributes;
|
||||
|
||||
OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (void **)&password);
|
||||
|
||||
if (status != noErr) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *passwordString = nil;
|
||||
|
||||
if (password != NULL) {
|
||||
char passwordBuffer[1024];
|
||||
|
||||
if (length > 1023) {
|
||||
length = 1023;
|
||||
}
|
||||
strncpy(passwordBuffer, password, length);
|
||||
|
||||
passwordBuffer[length] = '\0';
|
||||
passwordString = [NSString stringWithCString:passwordBuffer];
|
||||
}
|
||||
|
||||
SecKeychainItemFreeContent(&list, password);
|
||||
|
||||
CFRelease(item);
|
||||
|
||||
return passwordString;
|
||||
}
|
||||
|
||||
+ (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServerName: (NSString *) serverName updateExisting: (BOOL) updateExisting error: (NSError **) error {
|
||||
if (!username || !password || !serverName) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
return;
|
||||
}
|
||||
|
||||
OSStatus status = noErr;
|
||||
|
||||
SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServerName: serverName error: error];
|
||||
|
||||
if (*error && [*error code] != noErr) {
|
||||
return;
|
||||
}
|
||||
|
||||
*error = nil;
|
||||
|
||||
if (item) {
|
||||
status = SecKeychainItemModifyAttributesAndData(item,
|
||||
NULL,
|
||||
strlen([password UTF8String]),
|
||||
[password UTF8String]);
|
||||
|
||||
CFRelease(item);
|
||||
}
|
||||
else {
|
||||
status = SecKeychainAddGenericPassword(NULL,
|
||||
strlen([serverName UTF8String]),
|
||||
[serverName UTF8String],
|
||||
strlen([username UTF8String]),
|
||||
[username UTF8String],
|
||||
strlen([password UTF8String]),
|
||||
[password UTF8String],
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (status != noErr) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void) deleteItemForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error {
|
||||
if (!username || !serverName) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: 2000 userInfo: nil];
|
||||
return;
|
||||
}
|
||||
|
||||
*error = nil;
|
||||
|
||||
SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServerName: serverName error: error];
|
||||
|
||||
if (*error && [*error code] != noErr) {
|
||||
return;
|
||||
}
|
||||
|
||||
OSStatus status;
|
||||
|
||||
if (item) {
|
||||
status = SecKeychainItemDelete(item);
|
||||
|
||||
CFRelease(item);
|
||||
}
|
||||
|
||||
if (status != noErr) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
}
|
||||
}
|
||||
|
||||
+ (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error {
|
||||
if (!username || !serverName) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
*error = nil;
|
||||
|
||||
SecKeychainItemRef item;
|
||||
|
||||
OSStatus status = SecKeychainFindGenericPassword(NULL,
|
||||
strlen([serverName UTF8String]),
|
||||
[serverName UTF8String],
|
||||
strlen([username UTF8String]),
|
||||
[username UTF8String],
|
||||
NULL,
|
||||
NULL,
|
||||
&item);
|
||||
|
||||
if (status != noErr) {
|
||||
if (status != errSecItemNotFound) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
+ (NSString *) getPasswordForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error {
|
||||
if (!username || !serverName) {
|
||||
if (error != nil) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (error != nil) {
|
||||
*error = nil;
|
||||
}
|
||||
|
||||
// Set up a query dictionary with the base query attributes: item type (generic), username, and service
|
||||
|
||||
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, nil] autorelease];
|
||||
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serverName, nil] autorelease];
|
||||
|
||||
NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
|
||||
|
||||
// First do a query for attributes, in case we already have a Keychain item with no password data set.
|
||||
// One likely way such an incorrect item could have come about is due to the previous (incorrect)
|
||||
// version of this code (which set the password as a generic attribute instead of password data).
|
||||
|
||||
NSDictionary *attributeResult = NULL;
|
||||
NSMutableDictionary *attributeQuery = [query mutableCopy];
|
||||
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes];
|
||||
OSStatus status = SecItemCopyMatching((CFDictionaryRef) attributeQuery, (CFTypeRef *) &attributeResult);
|
||||
|
||||
[attributeResult release];
|
||||
[attributeQuery release];
|
||||
|
||||
if (status != noErr) {
|
||||
// No existing item found--simply return nil for the password
|
||||
if (error != nil && status != errSecItemNotFound) {
|
||||
//Only return an error if a real exception happened--not simply for "not found."
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// We have an existing item, now query for the password data associated with it.
|
||||
|
||||
NSData *resultData = nil;
|
||||
NSMutableDictionary *passwordQuery = [query mutableCopy];
|
||||
[passwordQuery setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];
|
||||
|
||||
status = SecItemCopyMatching((CFDictionaryRef) passwordQuery, (CFTypeRef *) &resultData);
|
||||
|
||||
[resultData autorelease];
|
||||
[passwordQuery release];
|
||||
|
||||
if (status != noErr) {
|
||||
if (status == errSecItemNotFound) {
|
||||
// We found attributes for the item previously, but no password now, so return a special error.
|
||||
// Users of this API will probably want to detect this error and prompt the user to
|
||||
// re-enter their credentials. When you attempt to store the re-entered credentials
|
||||
// using storeUsername:andPassword:forServiceName:updateExisting:error
|
||||
// the old, incorrect entry will be deleted and a new one with a properly encrypted
|
||||
// password will be added.
|
||||
if (error != nil) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Something else went wrong. Simply return the normal Keychain API error code.
|
||||
if (error != nil) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *password = nil;
|
||||
|
||||
if (resultData) {
|
||||
password = [[NSString alloc] initWithData: resultData encoding: NSUTF8StringEncoding];
|
||||
}
|
||||
else {
|
||||
// There is an existing item, but we weren't able to get password data for it for some reason,
|
||||
// Possibly as a result of an item being incorrectly entered by the previous code.
|
||||
// Set the -1999 error so the code above us can prompt the user again.
|
||||
if (error != nil) {
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil];
|
||||
}
|
||||
}
|
||||
|
||||
return [password autorelease];
|
||||
}
|
||||
|
||||
+ (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServerName: (NSString *) serverName updateExisting: (BOOL) updateExisting error: (NSError **) error
|
||||
{
|
||||
if (!username || !password || !serverName)
|
||||
{
|
||||
if (error != nil)
|
||||
{
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// See if we already have a password entered for these credentials.
|
||||
NSError *getError = nil;
|
||||
NSString *existingPassword = [SFHFKeychainUtils getPasswordForUsername: username andServerName: serverName error:&getError];
|
||||
|
||||
if ([getError code] == -1999)
|
||||
{
|
||||
// There is an existing entry without a password properly stored (possibly as a result of the previous incorrect version of this code.
|
||||
// Delete the existing item before moving on entering a correct one.
|
||||
|
||||
getError = nil;
|
||||
|
||||
[self deleteItemForUsername: username andServerName: serverName error: &getError];
|
||||
|
||||
if ([getError code] != noErr)
|
||||
{
|
||||
if (error != nil)
|
||||
{
|
||||
*error = getError;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
else if ([getError code] != noErr)
|
||||
{
|
||||
if (error != nil)
|
||||
{
|
||||
*error = getError;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (error != nil)
|
||||
{
|
||||
*error = nil;
|
||||
}
|
||||
|
||||
OSStatus status = noErr;
|
||||
|
||||
if (existingPassword)
|
||||
{
|
||||
// We have an existing, properly entered item with a password.
|
||||
// Update the existing item.
|
||||
|
||||
if (![existingPassword isEqualToString:password] && updateExisting)
|
||||
{
|
||||
//Only update if we're allowed to update existing. If not, simply do nothing.
|
||||
|
||||
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,
|
||||
kSecAttrService,
|
||||
kSecAttrLabel,
|
||||
kSecAttrAccount,
|
||||
nil] autorelease];
|
||||
|
||||
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,
|
||||
serverName,
|
||||
serverName,
|
||||
username,
|
||||
nil] autorelease];
|
||||
|
||||
NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
|
||||
|
||||
status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionary dictionaryWithObject: [password dataUsingEncoding: NSUTF8StringEncoding] forKey: (NSString *) kSecValueData]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No existing entry (or an existing, improperly entered, and therefore now
|
||||
// deleted, entry). Create a new entry.
|
||||
|
||||
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,
|
||||
kSecAttrService,
|
||||
kSecAttrLabel,
|
||||
kSecAttrAccount,
|
||||
kSecValueData,
|
||||
nil] autorelease];
|
||||
|
||||
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,
|
||||
serverName,
|
||||
serverName,
|
||||
username,
|
||||
[password dataUsingEncoding: NSUTF8StringEncoding],
|
||||
nil] autorelease];
|
||||
|
||||
NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
|
||||
|
||||
status = SecItemAdd((CFDictionaryRef) query, NULL);
|
||||
}
|
||||
|
||||
if (error != nil && status != noErr)
|
||||
{
|
||||
// Something went wrong with adding the new item. Return the Keychain error code.
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL) deleteItemForUsername: (NSString *) username andServerName: (NSString *) serverName error: (NSError **) error
|
||||
{
|
||||
if (!username || !serverName)
|
||||
{
|
||||
if (error != nil)
|
||||
{
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (error != nil)
|
||||
{
|
||||
*error = nil;
|
||||
}
|
||||
|
||||
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, kSecReturnAttributes, nil] autorelease];
|
||||
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serverName, kCFBooleanTrue, nil] autorelease];
|
||||
|
||||
NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
|
||||
|
||||
OSStatus status = SecItemDelete((CFDictionaryRef) query);
|
||||
|
||||
if (error != nil && status != noErr)
|
||||
{
|
||||
*error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Basic type defines for TSX RDC
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef TSXRemoteDesktop_TSXTypes_h
|
||||
#define TSXRemoteDesktop_TSXTypes_h
|
||||
|
||||
#pragma mark Internal state
|
||||
|
||||
// Represents the underlying state of a TWSession RDP connection.
|
||||
typedef enum _TSXConnectionState
|
||||
{
|
||||
TSXConnectionClosed = 0, // Session either hasn't begun connecting, or its connection has finished disconnecting.
|
||||
TSXConnectionConnecting = 1, // Session is in the process of establishing an RDP connection. A TCP or SSL connection might be established, but the RDP initialization sequence isn't finished.
|
||||
TSXConnectionConnected = 2, // Session has a full RDP connection established; though if the windows computer doesn't support NLA, a login screen might be shown in the session.
|
||||
TSXConnectionDisconnected = 3 // Session is disconnected at the RDP layer. TSX RDC might still be disposing of resources, however.
|
||||
} TSXConnectionState;
|
||||
|
||||
#pragma mark Session settings
|
||||
|
||||
// Represents the type of screen resolution the user has selected. Most are dynamic sizes, meaning that the actual session dimensions are calculated when connecting.
|
||||
typedef enum _TSXScreenOptions
|
||||
{
|
||||
TSXScreenOptionFixed = 0, // A static resolution, like 1024x768
|
||||
TSXScreenOptionFitScreen = 1, // Upon connection, fit the session to the entire screen size
|
||||
TSXScreenOptionCustom = 2, // Like fixed just specified by the user
|
||||
} TSXScreenOptions;
|
||||
|
||||
typedef enum _TSXAudioPlaybackOptions
|
||||
{
|
||||
TSXAudioPlaybackLocal = 0,
|
||||
TSXAudioPlaybackServer = 1,
|
||||
TSXAudioPlaybackSilent = 2
|
||||
} TSXAudioPlaybackOptions;
|
||||
|
||||
typedef enum _TSXProtocolSecurityOptions
|
||||
{
|
||||
TSXProtocolSecurityAutomatic = 0,
|
||||
TSXProtocolSecurityRDP = 1,
|
||||
TSXProtocolSecurityTLS = 2,
|
||||
TSXProtocolSecurityNLA = 3
|
||||
} TSXProtocolSecurityOptions;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Utility functions
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TSXTypes.h"
|
||||
|
||||
// helper macro to encode a table path into a tag value (used to identify controls in their delegate handlers)
|
||||
#define GET_TAG(section, row) ((((int)section) << 16) | ((int)(row)))
|
||||
#define GET_TAG_FROM_PATH(path) ((((int)path.section) << 16) | ((int)(path.row)))
|
||||
|
||||
|
||||
BOOL ScanHostNameAndPort(NSString* address, NSString** host, unsigned short* port);
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Screen Resolutions
|
||||
|
||||
NSString* ScreenResolutionDescription(TSXScreenOptions type, int width, int height);
|
||||
BOOL ScanScreenResolution(NSString* description, int* width, int* height, TSXScreenOptions* type);
|
||||
|
||||
NSDictionary* SelectionForColorSetting(void);
|
||||
NSArray* ResolutionModes(void);
|
||||
|
||||
#pragma mark Security Protocol
|
||||
|
||||
NSString* ProtocolSecurityDescription(TSXProtocolSecurityOptions type);
|
||||
BOOL ScanProtocolSecurity(NSString* description, TSXProtocolSecurityOptions* type);
|
||||
NSDictionary* SelectionForSecuritySetting(void);
|
||||
|
||||
#pragma mark Bookmarks
|
||||
@class BookmarkBase;
|
||||
NSMutableArray* FilterBookmarks(NSArray* bookmarks, NSArray* filter_words);
|
||||
NSMutableArray* FilterHistory(NSArray* history, NSString* filterStr);
|
||||
|
||||
#pragma mark iPad/iPhone detection
|
||||
|
||||
BOOL IsPad(void);
|
||||
BOOL IsPhone(void);
|
||||
|
||||
#pragma mark Version Info
|
||||
NSString* TSXAppFullVersion(void);
|
||||
|
||||
#pragma mark Touch/Mouse handling
|
||||
|
||||
// set mouse buttons swapped flag
|
||||
void SetSwapMouseButtonsFlag(BOOL swapped);
|
||||
|
||||
// set invert scrolling flag
|
||||
void SetInvertScrollingFlag(BOOL invert);
|
||||
|
||||
// return event value for left mouse button
|
||||
int GetLeftMouseButtonClickEvent(BOOL down);
|
||||
|
||||
// return event value for right mouse button
|
||||
int GetRightMouseButtonClickEvent(BOOL down);
|
||||
|
||||
// return event value for mouse move event
|
||||
int GetMouseMoveEvent(void);
|
||||
|
||||
// return mouse wheel event
|
||||
int GetMouseWheelEvent(BOOL down);
|
||||
|
||||
// scrolling gesture detection delta
|
||||
CGFloat GetScrollGestureDelta(void);
|
||||
|
||||
#pragma mark Connectivity tools
|
||||
// activates the iphone's WWAN interface in case it is offline
|
||||
void WakeUpWWAN(void);
|
||||
|
||||
#pragma mark System Info functions
|
||||
NSString* TSXGetPlatform(void);
|
||||
BOOL TSXDeviceHasJailBreak(void);
|
||||
NSString* TSXGetPrimaryMACAddress(NSString *sep);
|
||||
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
Utility functions
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "Utils.h"
|
||||
#import "OrderedDictionary.h"
|
||||
#import "TSXAdditions.h"
|
||||
|
||||
#import <freerdp/input.h>
|
||||
#import "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
BOOL ScanHostNameAndPort(NSString* address, NSString** host, unsigned short* port)
|
||||
{
|
||||
*host = @""; *port = 0;
|
||||
|
||||
if (![address length])
|
||||
return NO;
|
||||
|
||||
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"rdp://%@", address]];
|
||||
|
||||
if (!url || ![[url host] length])
|
||||
return NO;
|
||||
|
||||
*host = [url host];
|
||||
*port = [[url port] unsignedShortValue];
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Working with Screen Resolutions
|
||||
|
||||
NSString* LocalizedFitScreen()
|
||||
{
|
||||
return NSLocalizedString(@"Automatic", @"Screen resolution selector: Automatic resolution (Full Screen on iPad, reasonable size on iPhone)");
|
||||
}
|
||||
|
||||
NSString* LocalizedCustom()
|
||||
{
|
||||
return NSLocalizedString(@"Custom", @"Screen resolution selector: Custom");
|
||||
}
|
||||
|
||||
BOOL ScanScreenResolution(NSString* description, int* width, int* height, TSXScreenOptions* type)
|
||||
{
|
||||
*height = 0; *width = 0; *type = TSXScreenOptionFixed;
|
||||
|
||||
if ([description isEqualToString:LocalizedFitScreen()])
|
||||
{
|
||||
*type = TSXScreenOptionFitScreen;
|
||||
return YES;
|
||||
}
|
||||
else if ([description isEqualToString:LocalizedCustom()])
|
||||
{
|
||||
*type = TSXScreenOptionCustom;
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSArray* resolution_components = [description componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"x*×"]];
|
||||
|
||||
if ([resolution_components count] != 2)
|
||||
return NO;
|
||||
|
||||
*width = [[resolution_components objectAtIndex:0] intValue];
|
||||
*height = [[resolution_components objectAtIndex:1] intValue];
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString* ScreenResolutionDescription(TSXScreenOptions type, int width, int height)
|
||||
{
|
||||
if (type == TSXScreenOptionFitScreen)
|
||||
return LocalizedFitScreen();
|
||||
else if (type == TSXScreenOptionCustom)
|
||||
return LocalizedCustom();
|
||||
|
||||
return [NSString stringWithFormat:@"%dx%d", width, height];
|
||||
}
|
||||
|
||||
|
||||
NSDictionary* SelectionForColorSetting()
|
||||
{
|
||||
OrderedDictionary* dict = [OrderedDictionary dictionaryWithCapacity:3];
|
||||
[dict setValue:[NSNumber numberWithInt:16] forKey:NSLocalizedString(@"High Color (16 Bit)", @"16 bit color selection")];
|
||||
[dict setValue:[NSNumber numberWithInt:24] forKey:NSLocalizedString(@"True Color (24 Bit)", @"24 bit color selection")];
|
||||
[dict setValue:[NSNumber numberWithInt:32] forKey:NSLocalizedString(@"Highest Quality (32 Bit)", @"32 bit color selection")];
|
||||
return dict;
|
||||
}
|
||||
|
||||
NSArray* ResolutionModes()
|
||||
{
|
||||
NSArray* array = [NSArray arrayWithObjects:ScreenResolutionDescription(TSXScreenOptionFitScreen, 0, 0),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 640, 480),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 800, 600),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1024, 768),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1280, 1024),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 900),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 1050),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1600, 1200),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1080),
|
||||
ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1200),
|
||||
ScreenResolutionDescription(TSXScreenOptionCustom, 0, 0), nil];
|
||||
return array;
|
||||
}
|
||||
|
||||
#pragma mark Working with Security Protocols
|
||||
|
||||
NSString* LocalizedAutomaticSecurity()
|
||||
{
|
||||
return NSLocalizedString(@"Automatic", @"Automatic protocl security selection");
|
||||
}
|
||||
|
||||
NSString* ProtocolSecurityDescription(TSXProtocolSecurityOptions type)
|
||||
{
|
||||
if (type == TSXProtocolSecurityNLA)
|
||||
return @"NLA";
|
||||
else if (type == TSXProtocolSecurityTLS)
|
||||
return @"TLS";
|
||||
else if (type == TSXProtocolSecurityRDP)
|
||||
return @"RDP";
|
||||
|
||||
return LocalizedAutomaticSecurity();
|
||||
}
|
||||
|
||||
BOOL ScanProtocolSecurity(NSString* description, TSXProtocolSecurityOptions* type)
|
||||
{
|
||||
*type = TSXProtocolSecurityRDP;
|
||||
|
||||
if ([description isEqualToString:@"NLA"])
|
||||
{
|
||||
*type = TSXProtocolSecurityNLA;
|
||||
return YES;
|
||||
}
|
||||
else if ([description isEqualToString:@"TLS"])
|
||||
{
|
||||
*type = TSXProtocolSecurityTLS;
|
||||
return YES;
|
||||
}
|
||||
else if ([description isEqualToString:@"RDP"])
|
||||
{
|
||||
*type = TSXProtocolSecurityRDP;
|
||||
return YES;
|
||||
}
|
||||
else if ([description isEqualToString:LocalizedAutomaticSecurity()])
|
||||
{
|
||||
*type = TSXProtocolSecurityAutomatic;
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary* SelectionForSecuritySetting()
|
||||
{
|
||||
OrderedDictionary* dict = [OrderedDictionary dictionaryWithCapacity:4];
|
||||
[dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityAutomatic] forKey:ProtocolSecurityDescription(TSXProtocolSecurityAutomatic)];
|
||||
[dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityRDP] forKey:ProtocolSecurityDescription(TSXProtocolSecurityRDP)];
|
||||
[dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityTLS] forKey:ProtocolSecurityDescription(TSXProtocolSecurityTLS)];
|
||||
[dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityNLA] forKey:ProtocolSecurityDescription(TSXProtocolSecurityNLA)];
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Bookmarks
|
||||
|
||||
#import "Bookmark.h"
|
||||
|
||||
NSMutableArray* FilterBookmarks(NSArray* bookmarks, NSArray* filter_words)
|
||||
{
|
||||
NSMutableArray* matching_items = [NSMutableArray array];
|
||||
NSArray* searched_keys = [NSArray arrayWithObjects:@"label", @"params.hostname", @"params.username", @"params.domain", nil];
|
||||
|
||||
for (ComputerBookmark* cur_bookmark in bookmarks)
|
||||
{
|
||||
double match_score = 0.0;
|
||||
for (int i = 0; i < [searched_keys count]; i++)
|
||||
{
|
||||
NSString* val = [cur_bookmark valueForKeyPath:[searched_keys objectAtIndex:i]];
|
||||
|
||||
if (![val isKindOfClass:[NSString class]] || ![val length])
|
||||
continue;
|
||||
|
||||
for (NSString* word in filter_words)
|
||||
if ([val rangeOfString:word options:(NSCaseInsensitiveSearch | NSWidthInsensitiveSearch)].location != NSNotFound)
|
||||
match_score += (1.0 / [filter_words count]) * pow(2, [searched_keys count] - i);
|
||||
}
|
||||
|
||||
if (match_score > 0.001)
|
||||
[matching_items addObject:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
cur_bookmark, @"bookmark",
|
||||
[NSNumber numberWithFloat:match_score], @"score",
|
||||
nil]];
|
||||
}
|
||||
|
||||
[matching_items sortUsingComparator:^NSComparisonResult(NSDictionary* obj1, NSDictionary* obj2) {
|
||||
return [[obj2 objectForKey:@"score"] compare:[obj1 objectForKey:@"score"]];
|
||||
}];
|
||||
|
||||
return matching_items;
|
||||
}
|
||||
|
||||
NSMutableArray* FilterHistory(NSArray* history, NSString* filterStr)
|
||||
{
|
||||
NSMutableArray* result = [NSMutableArray array];
|
||||
for (NSString* item in history)
|
||||
{
|
||||
if ([item rangeOfString:filterStr].location != NSNotFound)
|
||||
[result addObject:item];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark Version Info
|
||||
NSString* TSXAppFullVersion()
|
||||
{
|
||||
NSDictionary* info_dict = [[NSBundle mainBundle] infoDictionary];
|
||||
return [NSString stringWithFormat:@"%@.%@ (%@)", [info_dict objectForKey:@"CFBundleShortVersionString"], [info_dict objectForKey:@"CFBundleVersion"], [NSString stringWithUTF8String:GIT_REVISION]];
|
||||
}
|
||||
|
||||
#pragma mark iPad/iPhone detection
|
||||
|
||||
BOOL IsPad()
|
||||
{
|
||||
#ifdef UI_USER_INTERFACE_IDIOM
|
||||
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
|
||||
#else
|
||||
return NO;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL IsPhone()
|
||||
{
|
||||
#ifdef UI_USER_INTERFACE_IDIOM
|
||||
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
|
||||
#else
|
||||
return NO;
|
||||
#endif
|
||||
}
|
||||
|
||||
// set mouse buttons swapped flag
|
||||
static BOOL g_swap_mouse_buttons = NO;
|
||||
void SetSwapMouseButtonsFlag(BOOL swapped)
|
||||
{
|
||||
g_swap_mouse_buttons = swapped;
|
||||
}
|
||||
|
||||
// set invert scrolling flag
|
||||
static BOOL g_invert_scrolling = NO;
|
||||
void SetInvertScrollingFlag(BOOL invert)
|
||||
{
|
||||
g_invert_scrolling = invert;
|
||||
}
|
||||
|
||||
// return event value for left mouse button
|
||||
int GetLeftMouseButtonClickEvent(BOOL down)
|
||||
{
|
||||
if (g_swap_mouse_buttons)
|
||||
return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0));
|
||||
else
|
||||
return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0));
|
||||
}
|
||||
|
||||
// return event value for right mouse button
|
||||
int GetRightMouseButtonClickEvent(BOOL down)
|
||||
{
|
||||
if (g_swap_mouse_buttons)
|
||||
return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0));
|
||||
else
|
||||
return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0));
|
||||
}
|
||||
|
||||
// get mouse move event
|
||||
int GetMouseMoveEvent()
|
||||
{
|
||||
return (PTR_FLAGS_MOVE);
|
||||
}
|
||||
|
||||
// return mouse wheel event
|
||||
int GetMouseWheelEvent(BOOL down)
|
||||
{
|
||||
if (g_invert_scrolling)
|
||||
down = !down;
|
||||
|
||||
if(down)
|
||||
return (PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | (0x0088));
|
||||
else
|
||||
return (PTR_FLAGS_WHEEL | (0x0078));
|
||||
}
|
||||
|
||||
// scrolling gesture detection delta
|
||||
CGFloat GetScrollGestureDelta()
|
||||
{
|
||||
return 10.0f;
|
||||
}
|
||||
|
||||
// this hack activates the iphone's WWAN interface in case it is offline
|
||||
void WakeUpWWAN()
|
||||
{
|
||||
NSURL * url = [[[NSURL alloc] initWithString:@"http://www.nonexistingdummyurl.com"] autorelease];
|
||||
//NSData * data =
|
||||
[NSData dataWithContentsOfURL:url]; // we don't need data but assigning one causes a "data not used" compiler warning
|
||||
}
|
||||
|
||||
|
||||
#pragma mark System Info functions
|
||||
|
||||
NSString* TSXGetPrimaryMACAddress(NSString *sep)
|
||||
{
|
||||
NSString* macaddress = @"";
|
||||
|
||||
struct ifaddrs *addrs;
|
||||
|
||||
if (getifaddrs(&addrs) < 0)
|
||||
{
|
||||
NSLog(@"getPrimaryMACAddress: getifaddrs failed.");
|
||||
return macaddress;
|
||||
}
|
||||
|
||||
for (struct ifaddrs *cursor = addrs; cursor!=NULL; cursor = cursor->ifa_next)
|
||||
{
|
||||
if(strcmp(cursor->ifa_name, "en0"))
|
||||
continue;
|
||||
if( (cursor->ifa_addr->sa_family == AF_LINK)
|
||||
&& (((struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == 0x6 /*IFT_ETHER*/))
|
||||
{
|
||||
struct sockaddr_dl *dlAddr = (struct sockaddr_dl *) cursor->ifa_addr;
|
||||
if(dlAddr->sdl_alen != 6)
|
||||
continue;
|
||||
unsigned char* base = (unsigned char *) &dlAddr->sdl_data[dlAddr->sdl_nlen];
|
||||
macaddress = [NSString hexStringFromData:base ofSize:6 withSeparator:sep afterNthChar:1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return macaddress;
|
||||
}
|
||||
|
||||
BOOL TSXDeviceHasJailBreak()
|
||||
{
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app/"])
|
||||
return YES;
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt/"])
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString* TSXGetPlatform()
|
||||
{
|
||||
size_t size;
|
||||
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
|
||||
char *machine = malloc(size);
|
||||
sysctlbyname("hw.machine", machine, &size, NULL, 0);
|
||||
NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
|
||||
free(machine);
|
||||
return platform;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Bookmark model abstraction
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ConnectionParams.h"
|
||||
|
||||
@interface ComputerBookmark : NSObject <NSCoding> {
|
||||
@protected
|
||||
ComputerBookmark* _parent;
|
||||
NSString* _uuid, * _label;
|
||||
UIImage* _image;
|
||||
ConnectionParams* _connection_params;
|
||||
BOOL _connected_via_wlan;
|
||||
}
|
||||
|
||||
@property (nonatomic,assign) ComputerBookmark* parent;
|
||||
@property (nonatomic,readonly) NSString* uuid;
|
||||
@property (nonatomic,copy) NSString* label;
|
||||
@property (nonatomic,retain) UIImage* image;
|
||||
@property (readonly, nonatomic) ConnectionParams* params;
|
||||
@property (nonatomic, assign) BOOL conntectedViaWLAN;
|
||||
|
||||
// Creates a copy of this object, with a new UUID
|
||||
- (id)copy;
|
||||
|
||||
// Whether user can delete, move, or rename this entry
|
||||
- (BOOL)isDeletable;
|
||||
- (BOOL)isMovable;
|
||||
- (BOOL)isRenamable;
|
||||
- (BOOL)hasImmutableHost;
|
||||
|
||||
- (id)initWithConnectionParameters:(ConnectionParams*)params;
|
||||
- (id)initWithBaseDefaultParameters;
|
||||
|
||||
// A copy of @params, with _bookmark_uuid set.
|
||||
- (ConnectionParams*)copyMarkedParams;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
Bookmark model abstraction
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import "Bookmark.h"
|
||||
#import "TSXAdditions.h"
|
||||
#import "Utils.h"
|
||||
|
||||
#import "GlobalDefaults.h"
|
||||
|
||||
@interface ComputerBookmark (Private)
|
||||
- (void)willChangeValueForKeyPath:(NSString *)keyPath;
|
||||
- (void)didChangeValueForKeyPath:(NSString *)keyPath;
|
||||
@end
|
||||
|
||||
@implementation ComputerBookmark
|
||||
|
||||
@synthesize parent=_parent, uuid=_uuid, label=_label, image=_image;
|
||||
@synthesize params=_connection_params, conntectedViaWLAN = _connected_via_wlan;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
_uuid = [[NSString stringWithUUID] retain];
|
||||
_label = @"";
|
||||
_connected_via_wlan = NO;
|
||||
return self;
|
||||
}
|
||||
|
||||
// Designated initializer.
|
||||
- (id)initWithConnectionParameters:(ConnectionParams*)params
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
_connection_params = [params copy];
|
||||
_connected_via_wlan = NO;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
if (!(self = [self init]))
|
||||
return nil;
|
||||
|
||||
if (![decoder allowsKeyedCoding])
|
||||
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
|
||||
|
||||
if ([decoder containsValueForKey:@"uuid"])
|
||||
{
|
||||
[_uuid release];
|
||||
_uuid = [[decoder decodeObjectForKey:@"uuid"] retain];
|
||||
}
|
||||
|
||||
if ([decoder containsValueForKey:@"label"])
|
||||
[self setLabel:[decoder decodeObjectForKey:@"label"]];
|
||||
|
||||
if ([decoder containsValueForKey:@"connectionParams"])
|
||||
{
|
||||
[_connection_params release];
|
||||
_connection_params = [[decoder decodeObjectForKey:@"connectionParams"] retain];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithBaseDefaultParameters
|
||||
{
|
||||
return [self initWithConnectionParameters:[[[ConnectionParams alloc] initWithBaseDefaultParameters] autorelease]];
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
ComputerBookmark* copy = [[[self class] alloc] init];
|
||||
[copy setLabel:[self label]];
|
||||
copy->_connection_params = [_connection_params copy];
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (![coder allowsKeyedCoding])
|
||||
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
|
||||
|
||||
[coder encodeObject:_uuid forKey:@"uuid"];
|
||||
[coder encodeObject:_label forKey:@"label"];
|
||||
[coder encodeObject:_connection_params forKey:@"connectionParams"];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_parent = nil;
|
||||
[_label release]; _label = nil;
|
||||
[_uuid release]; _uuid = nil;
|
||||
[_connection_params release]; _connection_params = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (UIImage*)image
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
return [object respondsToSelector:@selector(uuid)] && [[object uuid] isEqual:_uuid];
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return ([self label] != nil) ? [self label] : _uuid;
|
||||
}
|
||||
|
||||
- (BOOL)validateValue:(id *)val forKey:(NSString *)key error:(NSError **)error
|
||||
{
|
||||
NSString* string_value = *val;
|
||||
|
||||
if ([key isEqualToString:@"label"])
|
||||
{
|
||||
if (![[string_value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length])
|
||||
{
|
||||
if (error)
|
||||
*error = [NSError errorWithDomain:@"" code:NSKeyValueValidationError userInfo:
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
NSLocalizedString(@"Connection labels cannot be blank", @"Bookmark data validation: label blank title."), NSLocalizedDescriptionKey,
|
||||
NSLocalizedString(@"Please enter the short description of this Connection that will appear in the Connection list.", @"Bookmark data validation: label blank message."), NSLocalizedRecoverySuggestionErrorKey,
|
||||
nil]];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)validateValue:(id *)val forKeyPath:(NSString *)keyPath error:(NSError **)error
|
||||
{
|
||||
// Could be used to validate params.hostname, params.password, params.port, etc.
|
||||
return [super validateValue:val forKeyPath:keyPath error:error];
|
||||
}
|
||||
|
||||
- (BOOL)isDeletable { return YES; }
|
||||
- (BOOL)isMovable { return YES; }
|
||||
- (BOOL)isRenamable { return YES; }
|
||||
- (BOOL)hasImmutableHost { return NO; }
|
||||
|
||||
|
||||
#pragma mark Custom KVC
|
||||
|
||||
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
|
||||
{
|
||||
if ([keyPath isEqualToString:@"params.resolution"])
|
||||
{
|
||||
int width, height;
|
||||
TSXScreenOptions type;
|
||||
if (ScanScreenResolution(value, &width, &height, &type))
|
||||
{
|
||||
[_connection_params willChangeValueForKey:@"resolution"];
|
||||
[[self params] setInt:type forKey:@"screen_resolution_type"];
|
||||
|
||||
if (type == TSXScreenOptionFixed)
|
||||
{
|
||||
[[self params] setInt:width forKey:@"width"];
|
||||
[[self params] setInt:height forKey:@"height"];
|
||||
}
|
||||
[_connection_params didChangeValueForKey:@"resolution"];
|
||||
}
|
||||
else
|
||||
[NSException raise:NSInvalidArgumentException format:@"%s got invalid screen resolution '%@'", __func__, value];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self willChangeValueForKeyPath:keyPath];
|
||||
[super setValue:value forKeyPath:keyPath];
|
||||
[self didChangeValueForKeyPath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)valueForKeyPath:(NSString *)keyPath
|
||||
{
|
||||
if ([keyPath isEqualToString:@"params.resolution"])
|
||||
return ScreenResolutionDescription([[self params] intForKey:@"screen_resolution_type"], [[self params] intForKey:@"width"], [[self params] intForKey:@"height"]);
|
||||
|
||||
return [super valueForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue])
|
||||
[self willChangeValueForKeyPath:keyPath];
|
||||
else
|
||||
[self didChangeValueForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- (NSDictionary*)targetForChangeNotificationForKeyPath:(NSString*)keyPath
|
||||
{
|
||||
NSString* changed_key = keyPath;
|
||||
NSObject* changed_object = self;
|
||||
|
||||
if ([keyPath rangeOfString:@"params."].location == 0)
|
||||
{
|
||||
changed_key = [keyPath substringFromIndex:[@"params." length]];
|
||||
changed_object = _connection_params;
|
||||
}
|
||||
|
||||
return [NSDictionary dictionaryWithObjectsAndKeys:changed_key, @"key", changed_object, @"object", nil];
|
||||
}
|
||||
|
||||
- (void)willChangeValueForKeyPath:(NSString *)keyPath
|
||||
{
|
||||
NSDictionary* target = [self targetForChangeNotificationForKeyPath:keyPath];
|
||||
[[target objectForKey:@"object"] willChangeValueForKey:[target objectForKey:@"key"]];
|
||||
}
|
||||
|
||||
- (void)didChangeValueForKeyPath:(NSString *)keyPath
|
||||
{
|
||||
NSDictionary* target = [self targetForChangeNotificationForKeyPath:keyPath];
|
||||
[[target objectForKey:@"object"] didChangeValueForKey:[target objectForKey:@"key"]];
|
||||
}
|
||||
|
||||
- (ConnectionParams*)copyMarkedParams
|
||||
{
|
||||
ConnectionParams* param_copy = [[self params] copy];
|
||||
[param_copy setValue:[self uuid] forKey:@"_bookmark_uuid"];
|
||||
return param_copy;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark No children
|
||||
- (NSUInteger)numberOfChildren { return 0; }
|
||||
- (NSUInteger)numberOfDescendants { return 1; }
|
||||
- (BookmarkBase *)childAtIndex:(NSUInteger)index { return nil; }
|
||||
- (NSUInteger)indexOfChild:(BookmarkBase *)child { return 0; }
|
||||
- (void)removeChild:(BookmarkBase *)child { }
|
||||
- (void)addChild:(BookmarkBase *)child { }
|
||||
- (void)addChild:(BookmarkBase *)child afterExistingChild:(BookmarkBase *)existingChild { }
|
||||
- (void)addChild:(BookmarkBase *)child atIndex:(NSInteger)index { }
|
||||
- (BOOL)hasDescendant:(BookmarkBase *)needle { return NO; }
|
||||
- (BOOL)canContainChildren { return NO; }
|
||||
@end
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Connection Parameters abstraction
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ConnectionParams : NSObject
|
||||
{
|
||||
@private
|
||||
NSMutableDictionary* _connection_params;
|
||||
}
|
||||
|
||||
// Designated initializer.
|
||||
- (id)initWithDictionary:(NSDictionary*)dict;
|
||||
- (id)initWithBaseDefaultParameters;
|
||||
|
||||
// Getting/setting values
|
||||
- (NSArray*)allKeys;
|
||||
- (void)setValue:(id)value forKey:(NSString *)key;
|
||||
- (id)valueForKey:(NSString*)key;
|
||||
- (BOOL)hasValueForKey:(NSString*)key;
|
||||
- (void)setInt:(int)integer forKey:(NSString*)key;
|
||||
- (int)intForKey:(NSString*)key;
|
||||
- (void)setBool:(BOOL)v forKey:(NSString*)key;
|
||||
- (BOOL)boolForKey:(NSString*)key;
|
||||
- (const char*)UTF8StringForKey:(NSString*)key;
|
||||
- (NSString*)StringForKey:(NSString*)key;
|
||||
|
||||
- (BOOL)hasValueForKeyPath:(NSString*)key;
|
||||
- (void)setInt:(int)integer forKeyPath:(NSString*)key;
|
||||
- (int)intForKeyPath:(NSString*)key;
|
||||
- (void)setBool:(BOOL)v forKeyPath:(NSString*)key;
|
||||
- (BOOL)boolForKeyPath:(NSString*)key;
|
||||
- (const char*)UTF8StringForKeyPath:(NSString*)key;
|
||||
- (NSString*)StringForKeyPath:(NSString*)key;
|
||||
|
||||
|
||||
- (int)intForKey:(NSString*)key with3GEnabled:(BOOL)enabled;
|
||||
- (BOOL)boolForKey:(NSString*)key with3GEnabled:(BOOL)enabled;
|
||||
|
||||
@end
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
Connection Parameters abstraction
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import "ConnectionParams.h"
|
||||
#import "GlobalDefaults.h"
|
||||
#import "EncryptionController.h"
|
||||
#import "Utils.h"
|
||||
#import "TSXAdditions.h"
|
||||
|
||||
@interface ConnectionParams (Private)
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params;
|
||||
@end
|
||||
|
||||
@implementation ConnectionParams
|
||||
|
||||
// Designated initializer.
|
||||
- (id)initWithDictionary:(NSDictionary*)dict
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
_connection_params = [dict mutableDeepCopy];
|
||||
|
||||
if ([[_connection_params objectForKey:@"password"] isKindOfClass:[NSData class]])
|
||||
{
|
||||
NSString* plaintext_password = [[[EncryptionController sharedEncryptionController] decryptor] decryptString:[_connection_params objectForKey:@"password"]];
|
||||
|
||||
[self setValue:plaintext_password forKey:@"password"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithBaseDefaultParameters
|
||||
{
|
||||
return [self initWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"TSXDefaultComputerBookmarkSettings"]];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithDictionary:[NSDictionary dictionary]];
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params
|
||||
{
|
||||
return [self initWithDictionary:params->_connection_params];
|
||||
}
|
||||
- (void)dealloc
|
||||
{
|
||||
[_connection_params release]; _connection_params = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [[ConnectionParams alloc] initWithDictionary:_connection_params];
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"ConnectionParams: %@", [_connection_params description]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark NSCoder
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
if ([decoder containsValueForKey:@"connectionParams"])
|
||||
return [self initWithDictionary:[decoder decodeObjectForKey:@"connectionParams"]];
|
||||
|
||||
return [self init];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
NSSet* unserializable_keys = [NSSet setWithObjects:@"view", nil];
|
||||
NSMutableDictionary* serializable_params = [[NSMutableDictionary alloc] initWithCapacity:[_connection_params count]];
|
||||
|
||||
for (NSString* k in _connection_params)
|
||||
if ( ([k characterAtIndex:0] != '_') && ![unserializable_keys containsObject:k])
|
||||
[serializable_params setObject:[_connection_params objectForKey:k] forKey:k];
|
||||
|
||||
if ([serializable_params objectForKey:@"password"] != nil)
|
||||
{
|
||||
NSData* encrypted_password = [[[EncryptionController sharedEncryptionController] encryptor] encryptString:[serializable_params objectForKey:@"password"]];
|
||||
|
||||
if (encrypted_password)
|
||||
[serializable_params setObject:encrypted_password forKey:@"password"];
|
||||
else
|
||||
[serializable_params removeObjectForKey:@"password"];
|
||||
}
|
||||
|
||||
[coder encodeObject:serializable_params forKey:@"connectionParams"];
|
||||
[serializable_params release];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark NSKeyValueCoding
|
||||
|
||||
- (void)setValue:(id)value forKey:(NSString *)key
|
||||
{
|
||||
[self willChangeValueForKey:key];
|
||||
|
||||
if (value == nil)
|
||||
[self setNilValueForKey:key];
|
||||
else
|
||||
[_connection_params setValue:value forKey:key];
|
||||
|
||||
[self didChangeValueForKey:key];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)value forKeyPath:(NSString *)key
|
||||
{
|
||||
[self willChangeValueForKey:key];
|
||||
|
||||
if (value == nil)
|
||||
[self setNilValueForKey:key];
|
||||
else
|
||||
[_connection_params setValue:value forKeyPath:key];
|
||||
|
||||
[self didChangeValueForKey:key];
|
||||
}
|
||||
|
||||
- (void)setNilValueForKey:(NSString *)key
|
||||
{
|
||||
[_connection_params removeObjectForKey:key];
|
||||
}
|
||||
|
||||
- (id)valueForKey:(NSString*)key
|
||||
{
|
||||
return [_connection_params valueForKey:key];
|
||||
}
|
||||
|
||||
- (NSArray*)allKeys
|
||||
{
|
||||
return [_connection_params allKeys];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark KV convenience
|
||||
|
||||
- (BOOL)hasValueForKey:(NSString*)key
|
||||
{
|
||||
return [_connection_params objectForKey:key] != nil;
|
||||
}
|
||||
|
||||
- (void)setInt:(int)integer forKey:(NSString*)key
|
||||
{
|
||||
[self setValue:[NSNumber numberWithInteger:integer] forKey:key];
|
||||
}
|
||||
- (int)intForKey:(NSString*)key
|
||||
{
|
||||
return [[self valueForKey:key] intValue];
|
||||
}
|
||||
|
||||
|
||||
- (void)setBool:(BOOL)v forKey:(NSString*)key
|
||||
{
|
||||
[self setValue:[NSNumber numberWithBool:v] forKey:key];
|
||||
}
|
||||
- (BOOL)boolForKey:(NSString*)key
|
||||
{
|
||||
return [[_connection_params objectForKey:key] boolValue];
|
||||
}
|
||||
|
||||
|
||||
- (const char*)UTF8StringForKey:(NSString*)key
|
||||
{
|
||||
id val = [self valueForKey:key];
|
||||
const char* str;
|
||||
|
||||
if ([val respondsToSelector:@selector(UTF8String)] && (str = [val UTF8String]))
|
||||
return str;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
- (NSString*)StringForKey:(NSString*)key
|
||||
{
|
||||
return [self valueForKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)hasValueForKeyPath:(NSString*)key
|
||||
{
|
||||
return [_connection_params valueForKeyPath:key] != nil;
|
||||
}
|
||||
|
||||
- (void)setInt:(int)integer forKeyPath:(NSString*)key
|
||||
{
|
||||
[self setValue:[NSNumber numberWithInteger:integer] forKeyPath:key];
|
||||
}
|
||||
- (int)intForKeyPath:(NSString*)key
|
||||
{
|
||||
return [[self valueForKeyPath:key] intValue];
|
||||
}
|
||||
|
||||
- (void)setBool:(BOOL)v forKeyPath:(NSString*)key
|
||||
{
|
||||
[self setValue:[NSNumber numberWithBool:v] forKeyPath:key];
|
||||
}
|
||||
|
||||
- (BOOL)boolForKeyPath:(NSString*)key
|
||||
{
|
||||
return [[self valueForKeyPath:key] boolValue];
|
||||
}
|
||||
|
||||
- (const char*)UTF8StringForKeyPath:(NSString*)key
|
||||
{
|
||||
id val = [self valueForKeyPath:key];
|
||||
const char* str;
|
||||
|
||||
if ([val respondsToSelector:@selector(UTF8String)] && (str = [val UTF8String]))
|
||||
return str;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
- (NSString*)StringForKeyPath:(NSString*)key
|
||||
{
|
||||
return [self valueForKeyPath:key];
|
||||
}
|
||||
|
||||
- (int)intForKey:(NSString*)key with3GEnabled:(BOOL)enabled
|
||||
{
|
||||
if (enabled && [self boolForKey:@"enable_3g_settings"])
|
||||
return [self intForKeyPath:[NSString stringWithFormat:@"settings_3g.%@", key]];
|
||||
return [self intForKeyPath:key];
|
||||
}
|
||||
|
||||
- (BOOL)boolForKey:(NSString*)key with3GEnabled:(BOOL)enabled
|
||||
{
|
||||
if (enabled && [self boolForKey:@"enable_3g_settings"])
|
||||
return [self boolForKeyPath:[NSString stringWithFormat:@"settings_3g.%@", key]];
|
||||
return [self boolForKeyPath:key];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Password Encryptor
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* Encrypts data using AES 128 with a 256 bit key derived using PBKDF2-HMAC-SHA1 */
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Encryption block cipher config
|
||||
#define TSXEncryptorBlockCipherAlgo kCCAlgorithmAES128
|
||||
#define TSXEncryptorBlockCipherKeySize kCCKeySizeAES256
|
||||
#define TSXEncryptorBlockCipherOptions kCCOptionPKCS7Padding
|
||||
#define TSXEncryptorBlockCipherBlockSize 16
|
||||
|
||||
// Key generation: If any of these are changed, existing password stores will no longer work
|
||||
#define TSXEncryptorPBKDF2Rounds 100
|
||||
#define TSXEncryptorPBKDF2Salt "9D¶3L}S¿lA[e€3C«"
|
||||
#define TSXEncryptorPBKDF2SaltLen TSXEncryptorBlockCipherOptions
|
||||
#define TSXEncryptorPBKDF2KeySize TSXEncryptorBlockCipherKeySize
|
||||
|
||||
|
||||
@interface Encryptor : NSObject {
|
||||
@private
|
||||
NSData* _encryption_key;
|
||||
NSString* _plaintext_password;
|
||||
}
|
||||
|
||||
@property(readonly) NSString* plaintextPassword;
|
||||
|
||||
- (id)initWithPassword:(NSString*)plaintext_password;
|
||||
|
||||
- (NSData*)encryptData:(NSData*)plaintext_data;
|
||||
- (NSData*)decryptData:(NSData*)encrypted_data;
|
||||
- (NSData*)encryptString:(NSString*)plaintext_string;
|
||||
- (NSString*)decryptString:(NSData*)encrypted_string;
|
||||
|
||||
@end
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
Password Encryptor
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* We try to use CommonCrypto as much as possible. PBKDF2 was added to CommonCrypto in iOS 5, so use OpenSSL only as a fallback to do PBKDF2 on pre iOS 5 systems. */
|
||||
|
||||
#import "Encryptor.h"
|
||||
#import <CommonCrypto/CommonKeyDerivation.h>
|
||||
#import <CommonCrypto/CommonCryptor.h>
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import <openssl/evp.h> // For PBKDF2 on < 5.0
|
||||
#include <fcntl.h>
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface Encryptor (Private)
|
||||
- (NSData*)randomInitializationVector;
|
||||
@end
|
||||
|
||||
@implementation Encryptor
|
||||
@synthesize plaintextPassword=_plaintext_password;
|
||||
|
||||
- (id)initWithPassword:(NSString*)plaintext_password
|
||||
{
|
||||
if (plaintext_password == nil)
|
||||
return nil;
|
||||
|
||||
if ( !(self = [super init]) )
|
||||
return nil;
|
||||
|
||||
_plaintext_password = [plaintext_password retain];
|
||||
const char* plaintext_password_data = [plaintext_password length] ? [plaintext_password UTF8String] : " ";
|
||||
|
||||
if (!plaintext_password_data || !strlen(plaintext_password_data))
|
||||
[NSException raise:NSInternalInconsistencyException format:@"%s: plaintext password data is zero length!", __func__];
|
||||
|
||||
|
||||
uint8_t* derived_key = calloc(1, TSXEncryptorPBKDF2KeySize);
|
||||
|
||||
if (CCKeyDerivationPBKDF != NULL)
|
||||
{
|
||||
int rounds = CCCalibratePBKDF(kCCPBKDF2, strlen(plaintext_password_data), TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, TSXEncryptorPBKDF2KeySize, 100);
|
||||
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data)-1, (const uint8_t*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, rounds, derived_key, TSXEncryptorPBKDF2KeySize);
|
||||
//NSLog(@"CCKeyDerivationPBKDF ret = %d; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
NSLog(@"%s: CCKeyDerivationPBKDF ret == %d, indicating some sort of failure.", __func__, ret);
|
||||
[self autorelease];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// iOS 4.x or earlier -- use OpenSSL
|
||||
unsigned long ret = PKCS5_PBKDF2_HMAC_SHA1(plaintext_password_data, (int)strlen(plaintext_password_data)-1, (const unsigned char*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, TSXEncryptorPBKDF2Rounds, TSXEncryptorPBKDF2KeySize, derived_key);
|
||||
//NSLog(@"PKCS5_PBKDF2_HMAC_SHA1 ret = %lu; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
|
||||
|
||||
if (ret != 1)
|
||||
{
|
||||
NSLog(@"%s: PKCS5_PBKDF2_HMAC_SHA1 ret == %lu, indicating some sort of failure.", __func__, ret);
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_encryption_key = [[NSData alloc] initWithBytesNoCopy:derived_key length:TSXEncryptorPBKDF2KeySize freeWhenDone:YES];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Encrypting/Decrypting data
|
||||
|
||||
- (NSData*)encryptData:(NSData*)plaintext_data
|
||||
{
|
||||
if (![plaintext_data length])
|
||||
return nil;
|
||||
|
||||
NSData* iv = [self randomInitializationVector];
|
||||
NSMutableData* encrypted_data = [NSMutableData dataWithLength:[iv length] + [plaintext_data length] + TSXEncryptorBlockCipherBlockSize];
|
||||
[encrypted_data replaceBytesInRange:NSMakeRange(0, [iv length]) withBytes:[iv bytes]];
|
||||
|
||||
size_t data_out_moved = 0;
|
||||
int ret = CCCrypt(kCCEncrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions, [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [iv bytes], [plaintext_data bytes], [plaintext_data length], [encrypted_data mutableBytes]+[iv length], [encrypted_data length]-[iv length], &data_out_moved);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case kCCSuccess:
|
||||
[encrypted_data setLength:[iv length] + data_out_moved];
|
||||
return encrypted_data;
|
||||
|
||||
default:
|
||||
NSLog(@"%s: uncaught error, ret CCCryptorStatus = %d (plaintext len = %lu; buffer size = %lu)", __func__, ret, (unsigned long)[plaintext_data length], (unsigned long)([encrypted_data length]-[iv length]));
|
||||
return nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData*)decryptData:(NSData*)encrypted_data
|
||||
{
|
||||
if ([encrypted_data length] <= TSXEncryptorBlockCipherBlockSize)
|
||||
return nil;
|
||||
|
||||
NSMutableData* plaintext_data = [NSMutableData dataWithLength:[encrypted_data length] + TSXEncryptorBlockCipherBlockSize];
|
||||
size_t data_out_moved = 0;
|
||||
|
||||
int ret = CCCrypt(kCCDecrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions, [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [encrypted_data bytes], [encrypted_data bytes] + TSXEncryptorBlockCipherBlockSize, [encrypted_data length] - TSXEncryptorBlockCipherBlockSize, [plaintext_data mutableBytes], [plaintext_data length], &data_out_moved);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case kCCSuccess:
|
||||
[plaintext_data setLength:data_out_moved];
|
||||
return plaintext_data;
|
||||
|
||||
case kCCBufferTooSmall: // Our output buffer is big enough to decrypt valid data. This return code indicates malformed data.
|
||||
case kCCAlignmentError: // Shouldn't get this, since we're using padding.
|
||||
case kCCDecodeError: // Wrong key.
|
||||
return nil;
|
||||
|
||||
default:
|
||||
NSLog(@"%s: uncaught error, ret CCCryptorStatus = %d (encrypted data len = %lu; buffer size = %lu; dom = %lu)", __func__, ret, (unsigned long)[encrypted_data length], (unsigned long)[plaintext_data length], data_out_moved);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSData*)encryptString:(NSString*)plaintext_string
|
||||
{
|
||||
return [self encryptData:[plaintext_string dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
- (NSString*)decryptString:(NSData*)encrypted_string
|
||||
{
|
||||
return [[[NSString alloc] initWithData:[self decryptData:encrypted_string] encoding:NSUTF8StringEncoding] autorelease];
|
||||
}
|
||||
|
||||
- (NSData*)randomInitializationVector
|
||||
{
|
||||
NSMutableData* iv = [NSMutableData dataWithLength:TSXEncryptorBlockCipherBlockSize];
|
||||
int fd;
|
||||
|
||||
if ( (fd = open("/dev/urandom", O_RDONLY)) < 0)
|
||||
return nil;
|
||||
|
||||
NSInteger bytes_needed = [iv length];
|
||||
char* p = [iv mutableBytes];
|
||||
|
||||
while (bytes_needed)
|
||||
{
|
||||
long bytes_read = read(fd, p, bytes_needed);
|
||||
|
||||
if (bytes_read < 0)
|
||||
continue;
|
||||
|
||||
p += bytes_read;
|
||||
bytes_needed -= bytes_read;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return iv;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Global default bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ConnectionParams, ComputerBookmark;
|
||||
|
||||
@interface GlobalDefaults : NSObject{
|
||||
@private
|
||||
ComputerBookmark* _default_bookmark;
|
||||
}
|
||||
|
||||
+ (GlobalDefaults*)sharedGlobalDefaults;
|
||||
|
||||
// The same object is always returned from this method.
|
||||
@property (readonly,nonatomic) ComputerBookmark* bookmark;
|
||||
|
||||
- (ConnectionParams*)newParams;
|
||||
- (ComputerBookmark*)newBookmark;
|
||||
|
||||
@end
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Global default bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "GlobalDefaults.h"
|
||||
#import "Bookmark.h"
|
||||
#import "ConnectionParams.h"
|
||||
|
||||
@implementation GlobalDefaults
|
||||
|
||||
+ (GlobalDefaults*)sharedGlobalDefaults
|
||||
{
|
||||
static GlobalDefaults* _shared_global_defaults = nil;
|
||||
|
||||
if (_shared_global_defaults == nil)
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (_shared_global_defaults == nil)
|
||||
_shared_global_defaults = [[GlobalDefaults alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
return _shared_global_defaults;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
ComputerBookmark* bookmark = nil;
|
||||
NSData* bookmark_data = [[NSUserDefaults standardUserDefaults] objectForKey:@"TSXSharedGlobalDefaultBookmark"];
|
||||
|
||||
if (bookmark_data && [bookmark_data length])
|
||||
bookmark = [NSKeyedUnarchiver unarchiveObjectWithData:bookmark_data];
|
||||
|
||||
if (!bookmark)
|
||||
bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
|
||||
|
||||
_default_bookmark = [bookmark retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_default_bookmark release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@synthesize bookmark=_default_bookmark;
|
||||
|
||||
- (ComputerBookmark*)newBookmark
|
||||
{
|
||||
return [[ComputerBookmark alloc] initWithConnectionParameters:[[self newParams] autorelease]];
|
||||
}
|
||||
|
||||
- (ConnectionParams*)newParams
|
||||
{
|
||||
ConnectionParams* param_copy = [[[self bookmark] params] copy];
|
||||
return param_copy;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
RDP Keyboard helper
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RDPSession.h"
|
||||
|
||||
@class RDPKeyboard;
|
||||
|
||||
|
||||
@protocol RDPKeyboardDelegate <NSObject>
|
||||
@optional
|
||||
- (void)modifiersChangedForKeyboard:(RDPKeyboard*)keyboard;
|
||||
@end
|
||||
|
||||
|
||||
@interface RDPKeyboard : NSObject {
|
||||
|
||||
RDPSession* _session;
|
||||
|
||||
int _virtual_key_map[256];
|
||||
int _unicode_map[256];
|
||||
NSDictionary* _special_keys;
|
||||
|
||||
NSObject<RDPKeyboardDelegate>* _delegate;
|
||||
|
||||
BOOL _ctrl_pressed;
|
||||
BOOL _alt_pressed;
|
||||
BOOL _shift_pressed;
|
||||
BOOL _win_pressed;
|
||||
}
|
||||
|
||||
@property (assign) id <RDPKeyboardDelegate> delegate;
|
||||
@property (readonly) BOOL ctrlPressed;
|
||||
@property (readonly) BOOL altPressed;
|
||||
@property (readonly) BOOL shiftPressed;
|
||||
@property (readonly) BOOL winPressed;
|
||||
|
||||
// returns a keyboard instance
|
||||
+ (RDPKeyboard*)getSharedRDPKeyboard;
|
||||
|
||||
// init the keyboard and assign the given rdp session and delegate
|
||||
- (void)initWithSession:(RDPSession*)session delegate:(NSObject<RDPKeyboardDelegate>*)delegate;
|
||||
|
||||
// called to reset any pending key states (i.e. pressed modifier keys)
|
||||
- (void)reset;
|
||||
|
||||
// sends the given unicode character to the server
|
||||
- (void)sendUnicode:(int)character;
|
||||
|
||||
// send a key stroke event using the given virtual key code
|
||||
- (void)sendVirtualKeyCode:(int)keyCode;
|
||||
|
||||
// toggle ctrl key, returns true if pressed, otherwise false
|
||||
- (void)toggleCtrlKey;
|
||||
|
||||
// toggle alt key, returns true if pressed, otherwise false
|
||||
- (void)toggleAltKey;
|
||||
|
||||
// toggle shift key, returns true if pressed, otherwise false
|
||||
- (void)toggleShiftKey;
|
||||
|
||||
// toggle windows key, returns true if pressed, otherwise false
|
||||
- (void)toggleWinKey;
|
||||
|
||||
// send key strokes
|
||||
- (void)sendEnterKeyStroke;
|
||||
- (void)sendEscapeKeyStroke;
|
||||
- (void)sendBackspaceKeyStroke;
|
||||
|
||||
@end
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
RDP Keyboard helper
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "RDPKeyboard.h"
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
|
||||
@interface RDPKeyboard (Private)
|
||||
- (void)sendVirtualKey:(int)vKey up:(BOOL)up;
|
||||
- (void)handleSpecialKey:(int)character;
|
||||
- (void)handleAlphaNumChar:(int)character;
|
||||
- (void)notifyDelegateModifiersChanged;
|
||||
@end
|
||||
|
||||
@implementation RDPKeyboard
|
||||
|
||||
@synthesize delegate = _delegate, ctrlPressed = _ctrl_pressed, altPressed = _alt_pressed, shiftPressed = _shift_pressed, winPressed = _win_pressed;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if((self = [super init]) != nil)
|
||||
{
|
||||
[self initWithSession:nil delegate:nil];
|
||||
|
||||
memset(_virtual_key_map, 0, sizeof(_virtual_key_map));
|
||||
memset(_unicode_map, 0, sizeof(_unicode_map));
|
||||
|
||||
// init vkey map - used for alpha-num characters
|
||||
_virtual_key_map['0'] = VK_KEY_0;
|
||||
_virtual_key_map['1'] = VK_KEY_1;
|
||||
_virtual_key_map['2'] = VK_KEY_2;
|
||||
_virtual_key_map['3'] = VK_KEY_3;
|
||||
_virtual_key_map['4'] = VK_KEY_4;
|
||||
_virtual_key_map['5'] = VK_KEY_5;
|
||||
_virtual_key_map['6'] = VK_KEY_6;
|
||||
_virtual_key_map['7'] = VK_KEY_7;
|
||||
_virtual_key_map['8'] = VK_KEY_8;
|
||||
_virtual_key_map['9'] = VK_KEY_9;
|
||||
|
||||
_virtual_key_map['a'] = VK_KEY_A;
|
||||
_virtual_key_map['b'] = VK_KEY_B;
|
||||
_virtual_key_map['c'] = VK_KEY_C;
|
||||
_virtual_key_map['d'] = VK_KEY_D;
|
||||
_virtual_key_map['e'] = VK_KEY_E;
|
||||
_virtual_key_map['f'] = VK_KEY_F;
|
||||
_virtual_key_map['g'] = VK_KEY_G;
|
||||
_virtual_key_map['h'] = VK_KEY_H;
|
||||
_virtual_key_map['i'] = VK_KEY_I;
|
||||
_virtual_key_map['j'] = VK_KEY_J;
|
||||
_virtual_key_map['k'] = VK_KEY_K;
|
||||
_virtual_key_map['l'] = VK_KEY_L;
|
||||
_virtual_key_map['m'] = VK_KEY_M;
|
||||
_virtual_key_map['n'] = VK_KEY_N;
|
||||
_virtual_key_map['o'] = VK_KEY_O;
|
||||
_virtual_key_map['p'] = VK_KEY_P;
|
||||
_virtual_key_map['q'] = VK_KEY_Q;
|
||||
_virtual_key_map['r'] = VK_KEY_R;
|
||||
_virtual_key_map['s'] = VK_KEY_S;
|
||||
_virtual_key_map['t'] = VK_KEY_T;
|
||||
_virtual_key_map['u'] = VK_KEY_U;
|
||||
_virtual_key_map['v'] = VK_KEY_V;
|
||||
_virtual_key_map['w'] = VK_KEY_W;
|
||||
_virtual_key_map['x'] = VK_KEY_X;
|
||||
_virtual_key_map['y'] = VK_KEY_Y;
|
||||
_virtual_key_map['z'] = VK_KEY_Z;
|
||||
|
||||
// init scancode map - used for special characters
|
||||
_unicode_map['-'] = 45;
|
||||
_unicode_map['/'] = 47;
|
||||
_unicode_map[':'] = 58;
|
||||
_unicode_map[';'] = 59;
|
||||
_unicode_map['('] = 40;
|
||||
_unicode_map[')'] = 41;
|
||||
_unicode_map['&'] = 38;
|
||||
_unicode_map['@'] = 64;
|
||||
_unicode_map['.'] = 46;
|
||||
_unicode_map[','] = 44;
|
||||
_unicode_map['?'] = 63;
|
||||
_unicode_map['!'] = 33;
|
||||
_unicode_map['\''] = 39;
|
||||
_unicode_map['\"'] = 34;
|
||||
|
||||
_unicode_map['['] = 91;
|
||||
_unicode_map[']'] = 93;
|
||||
_unicode_map['{'] = 123;
|
||||
_unicode_map['}'] = 125;
|
||||
_unicode_map['#'] = 35;
|
||||
_unicode_map['%'] = 37;
|
||||
_unicode_map['^'] = 94;
|
||||
_unicode_map['*'] = 42;
|
||||
_unicode_map['+'] = 43;
|
||||
_unicode_map['='] = 61;
|
||||
|
||||
_unicode_map['_'] = 95;
|
||||
_unicode_map['\\'] = 92;
|
||||
_unicode_map['|'] = 124;
|
||||
_unicode_map['~'] = 126;
|
||||
_unicode_map['<'] = 60;
|
||||
_unicode_map['>'] = 62;
|
||||
_unicode_map['$'] = 36;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark class methods
|
||||
|
||||
// return a keyboard instance
|
||||
+ (RDPKeyboard*)getSharedRDPKeyboard
|
||||
{
|
||||
static RDPKeyboard* _shared_keyboard = nil;
|
||||
|
||||
if (_shared_keyboard == nil)
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (_shared_keyboard == nil)
|
||||
_shared_keyboard = [[RDPKeyboard alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
return _shared_keyboard;
|
||||
}
|
||||
|
||||
// reset the keyboard instance and assign the given rdp instance
|
||||
- (void)initWithSession:(RDPSession *)session delegate:(NSObject<RDPKeyboardDelegate> *)delegate
|
||||
{
|
||||
_alt_pressed = NO;
|
||||
_ctrl_pressed = NO;
|
||||
_shift_pressed = NO;
|
||||
_win_pressed = NO;
|
||||
|
||||
_session = session;
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
// reset pressed ctrl, alt, shift or win key
|
||||
if(_shift_pressed)
|
||||
[self toggleShiftKey];
|
||||
if(_alt_pressed)
|
||||
[self toggleAltKey];
|
||||
if(_ctrl_pressed)
|
||||
[self toggleCtrlKey];
|
||||
if(_win_pressed)
|
||||
[self toggleWinKey];
|
||||
}
|
||||
|
||||
// handles button pressed input event from the iOS keyboard
|
||||
// performs all conversions etc.
|
||||
- (void)sendUnicode:(int)character
|
||||
{
|
||||
if(isalnum(character))
|
||||
[self handleAlphaNumChar:character];
|
||||
else
|
||||
[self handleSpecialKey:character];
|
||||
|
||||
[self reset];
|
||||
}
|
||||
|
||||
// send a backspace key press
|
||||
- (void)sendVirtualKeyCode:(int)keyCode
|
||||
{
|
||||
[self sendVirtualKey:keyCode up:NO];
|
||||
[self sendVirtualKey:keyCode up:YES];
|
||||
}
|
||||
|
||||
#pragma mark modifier key handling
|
||||
// toggle ctrl key, returns true if pressed, otherwise false
|
||||
- (void)toggleCtrlKey
|
||||
{
|
||||
[self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
|
||||
_ctrl_pressed = !_ctrl_pressed;
|
||||
[self notifyDelegateModifiersChanged];
|
||||
}
|
||||
|
||||
// toggle alt key, returns true if pressed, otherwise false
|
||||
- (void)toggleAltKey
|
||||
{
|
||||
[self sendVirtualKey:VK_LMENU up:_alt_pressed];
|
||||
_alt_pressed = !_alt_pressed;
|
||||
[self notifyDelegateModifiersChanged];
|
||||
}
|
||||
|
||||
// toggle shift key, returns true if pressed, otherwise false
|
||||
- (void)toggleShiftKey
|
||||
{
|
||||
[self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
|
||||
_shift_pressed = !_shift_pressed;
|
||||
[self notifyDelegateModifiersChanged];
|
||||
}
|
||||
|
||||
// toggle windows key, returns true if pressed, otherwise false
|
||||
- (void)toggleWinKey
|
||||
{
|
||||
[self sendVirtualKey:VK_LWIN up:_win_pressed];
|
||||
_win_pressed = !_win_pressed;
|
||||
[self notifyDelegateModifiersChanged];
|
||||
}
|
||||
|
||||
#pragma mark Sending special key strokes
|
||||
|
||||
- (void)sendEnterKeyStroke
|
||||
{
|
||||
[self sendVirtualKeyCode:VK_RETURN];
|
||||
}
|
||||
|
||||
- (void)sendEscapeKeyStroke
|
||||
{
|
||||
[self sendVirtualKeyCode:VK_ESCAPE];
|
||||
}
|
||||
|
||||
- (void)sendBackspaceKeyStroke
|
||||
{
|
||||
[self sendVirtualKeyCode:VK_BACK];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@implementation RDPKeyboard (Private)
|
||||
|
||||
- (void)handleAlphaNumChar:(int)character
|
||||
{
|
||||
// if we recive an uppercase letter - make it lower and send an shift down event to server
|
||||
BOOL shift_was_sent = NO;
|
||||
if(isupper(character) && _shift_pressed == NO)
|
||||
{
|
||||
character = tolower(character);
|
||||
[self sendVirtualKey:VK_SHIFT up:NO];
|
||||
shift_was_sent = YES;
|
||||
}
|
||||
|
||||
// convert the character to a VK
|
||||
int vk = _virtual_key_map[character];
|
||||
if(vk != 0)
|
||||
{
|
||||
// send key pressed
|
||||
[self sendVirtualKey:vk up:NO];
|
||||
[self sendVirtualKey:vk up:YES];
|
||||
}
|
||||
|
||||
// send the missing shift up if we had a shift down
|
||||
if(shift_was_sent)
|
||||
[self sendVirtualKey:VK_SHIFT up:YES];
|
||||
}
|
||||
|
||||
- (void)handleSpecialKey:(int)character
|
||||
{
|
||||
NSDictionary* eventDescriptor = nil;
|
||||
if(character < 256)
|
||||
{
|
||||
// convert the character to a unicode character
|
||||
int code = _unicode_map[character];
|
||||
if(code != 0)
|
||||
eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"keyboard", @"type",
|
||||
@"unicode", @"subtype",
|
||||
[NSNumber numberWithUnsignedShort:0], @"flags",
|
||||
[NSNumber numberWithUnsignedShort:code], @"unicode_char",
|
||||
nil];
|
||||
}
|
||||
|
||||
if (eventDescriptor == nil)
|
||||
eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"keyboard", @"type",
|
||||
@"unicode", @"subtype",
|
||||
[NSNumber numberWithUnsignedShort:0], @"flags",
|
||||
[NSNumber numberWithUnsignedShort:character], @"unicode_char",
|
||||
nil];
|
||||
|
||||
[_session sendInputEvent:eventDescriptor];
|
||||
}
|
||||
|
||||
// sends the vk code to the session
|
||||
- (void)sendVirtualKey:(int)vKey up:(BOOL)up
|
||||
{
|
||||
RDP_SCANCODE scancode = freerdp_keyboard_get_rdp_scancode_from_virtual_key_code(vKey);
|
||||
int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
|
||||
flags |= (RDP_SCANCODE_EXTENDED(scancode) ? KBD_FLAGS_EXTENDED : 0);
|
||||
[_session sendInputEvent:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"keyboard", @"type",
|
||||
@"scancode", @"subtype",
|
||||
[NSNumber numberWithUnsignedShort:flags], @"flags",
|
||||
[NSNumber numberWithUnsignedShort:RDP_SCANCODE_CODE(scancode)], @"scancode",
|
||||
nil]];
|
||||
}
|
||||
|
||||
- (void)notifyDelegateModifiersChanged
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
|
||||
[[self delegate] modifiersChangedForKeyboard:self];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
RDP Session object
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
// forward declaration
|
||||
@class RDPSession;
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
// notification handler for session disconnect
|
||||
extern NSString* TSXSessionDidDisconnectNotification;
|
||||
extern NSString* TSXSessionDidFailToConnectNotification;
|
||||
|
||||
// protocol for session notifications
|
||||
@protocol RDPSessionDelegate <NSObject>
|
||||
@optional
|
||||
- (void)session:(RDPSession*)session didFailToConnect:(int)reason;
|
||||
- (void)sessionWillConnect:(RDPSession*)session;
|
||||
- (void)sessionDidConnect:(RDPSession*)session;
|
||||
- (void)sessionWillDisconnect:(RDPSession*)session;
|
||||
- (void)sessionDidDisconnect:(RDPSession*)session;
|
||||
- (void)sessionBitmapContextWillChange:(RDPSession*)session;
|
||||
- (void)sessionBitmapContextDidChange:(RDPSession*)session;
|
||||
- (void)session:(RDPSession*)session needsRedrawInRect:(CGRect)rect;
|
||||
- (CGSize)sizeForFitScreenForSession:(RDPSession*)session;
|
||||
- (void)showGoProScreen:(RDPSession*)session;
|
||||
|
||||
- (void)session:(RDPSession*)session requestsAuthenticationWithParams:(NSMutableDictionary*)params;
|
||||
- (void)session:(RDPSession*)session verifyCertificateWithParams:(NSMutableDictionary*)params;
|
||||
|
||||
@end
|
||||
|
||||
// rdp session
|
||||
@interface RDPSession : NSObject
|
||||
{
|
||||
@private
|
||||
freerdp* _freerdp;
|
||||
|
||||
ComputerBookmark* _bookmark;
|
||||
|
||||
ConnectionParams* _params;
|
||||
|
||||
NSObject<RDPSessionDelegate>* _delegate;
|
||||
|
||||
NSCondition* _ui_request_completed;
|
||||
|
||||
NSString* _name;
|
||||
|
||||
// flag if the session is suspended
|
||||
BOOL _suspended;
|
||||
|
||||
// flag that specifies whether the RDP toolbar is visible
|
||||
BOOL _toolbar_visible;
|
||||
}
|
||||
|
||||
@property (readonly) ConnectionParams* params;
|
||||
@property (readonly) ComputerBookmark* bookmark;
|
||||
@property (assign) id <RDPSessionDelegate> delegate;
|
||||
@property (assign) BOOL toolbarVisible;
|
||||
@property (readonly) CGContextRef bitmapContext;
|
||||
@property (readonly) NSCondition* uiRequestCompleted;
|
||||
|
||||
|
||||
// initialize a new session with the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
#pragma mark - session control functions
|
||||
|
||||
// connect the session
|
||||
-(void)connect;
|
||||
|
||||
// disconnect session
|
||||
-(void)disconnect;
|
||||
|
||||
// suspends the session
|
||||
-(void)suspend;
|
||||
|
||||
// resumes a previously suspended session
|
||||
-(void)resume;
|
||||
|
||||
// returns YES if the session is started
|
||||
-(BOOL)isSuspended;
|
||||
|
||||
// send input event to the server
|
||||
-(void)sendInputEvent:(NSDictionary*)event;
|
||||
|
||||
// session needs a refresh of its view
|
||||
- (void)setNeedsDisplayInRectAsValue:(NSValue*)rect_value;
|
||||
|
||||
// get a small session screenshot
|
||||
- (UIImage*)getScreenshotWithSize:(CGSize)size;
|
||||
|
||||
// returns the session's current paramters
|
||||
- (rdpSettings*)getSessionParams;
|
||||
|
||||
// returns the session's name (usually the label of the bookmark the session was created with)
|
||||
- (NSString*)sessionName;
|
||||
|
||||
@end
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
RDP Session object
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "ios_freerdp.h"
|
||||
#import "ios_freerdp_ui.h"
|
||||
#import "ios_freerdp_events.h"
|
||||
|
||||
#import "RDPSession.h"
|
||||
#import "TSXTypes.h"
|
||||
#import "Bookmark.h"
|
||||
#import "ConnectionParams.h"
|
||||
|
||||
NSString* TSXSessionDidDisconnectNotification = @"TSXSessionDidDisconnect";
|
||||
NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect";
|
||||
|
||||
@interface RDPSession (Private)
|
||||
- (void)runSession;
|
||||
- (void)runSessionFinished:(NSNumber*)result;
|
||||
- (mfInfo*)mfi;
|
||||
|
||||
// The connection thread calls these on the main thread.
|
||||
- (void)sessionWillConnect;
|
||||
- (void)sessionDidConnect;
|
||||
- (void)sessionDidDisconnect;
|
||||
- (void)sessionDidFailToConnect:(int)reason;
|
||||
- (void)sessionBitmapContextWillChange;
|
||||
- (void)sessionBitmapContextDidChange;
|
||||
@end
|
||||
|
||||
@implementation RDPSession
|
||||
|
||||
@synthesize delegate=_delegate, params=_params, toolbarVisible = _toolbar_visible, uiRequestCompleted = _ui_request_completed, bookmark = _bookmark;
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
ios_init_freerdp();
|
||||
}
|
||||
|
||||
// Designated initializer.
|
||||
- (id)initWithBookmark:(ComputerBookmark *)bookmark
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
if (!bookmark)
|
||||
[NSException raise:NSInvalidArgumentException format:@"%s: params may not be nil.", __func__];
|
||||
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [[bookmark params] copy];
|
||||
_name = [[bookmark label] retain];
|
||||
_delegate = nil;
|
||||
_toolbar_visible = YES;
|
||||
_freerdp = ios_freerdp_new();
|
||||
rdpSettings* settings = _freerdp->settings;
|
||||
_ui_request_completed = [[NSCondition alloc] init];
|
||||
|
||||
BOOL connected_via_3g = ![bookmark conntectedViaWLAN];
|
||||
|
||||
// Screen Size is set on connect (we need a valid delegate in case the user choose an automatic screen size)
|
||||
|
||||
// Other simple numeric settings
|
||||
if ([_params hasValueForKey:@"colors"])
|
||||
settings->ColorDepth = [_params intForKey:@"colors" with3GEnabled:connected_via_3g];
|
||||
|
||||
if ([_params hasValueForKey:@"port"])
|
||||
settings->ServerPort = [_params intForKey:@"port"];
|
||||
|
||||
if ([_params boolForKey:@"console"])
|
||||
settings->ConsoleSession = 1;
|
||||
|
||||
// connection info
|
||||
settings->ServerHostname = strdup([_params UTF8StringForKey:@"hostname"]);
|
||||
|
||||
// String settings
|
||||
if ([[_params StringForKey:@"username"] length])
|
||||
settings->Username = strdup([_params UTF8StringForKey:@"username"]);
|
||||
|
||||
if ([[_params StringForKey:@"password"] length])
|
||||
settings->Password = strdup([_params UTF8StringForKey:@"password"]);
|
||||
|
||||
if ([[_params StringForKey:@"domain"] length])
|
||||
settings->Domain = strdup([_params UTF8StringForKey:@"domain"]);
|
||||
|
||||
settings->ShellWorkingDirectory = strdup([_params UTF8StringForKey:@"working_directory"]);
|
||||
settings->AlternateShell = strdup([_params UTF8StringForKey:@"remote_program"]);
|
||||
|
||||
|
||||
// RemoteFX
|
||||
if ([_params boolForKey:@"perf_remotefx" with3GEnabled:connected_via_3g])
|
||||
{
|
||||
settings->RemoteFxCodec = TRUE;
|
||||
settings->FastPathOutput = TRUE;
|
||||
settings->ColorDepth = 32;
|
||||
settings->LargePointerFlag = TRUE;
|
||||
settings->FrameMarkerCommandEnabled = TRUE;
|
||||
}
|
||||
|
||||
// Performance flags
|
||||
settings->DisableWallpaper = ![_params boolForKey:@"perf_show_desktop" with3GEnabled:connected_via_3g];
|
||||
settings->DisableFullWindowDrag = ![_params boolForKey:@"perf_window_dragging" with3GEnabled:connected_via_3g];
|
||||
settings->DisableMenuAnims = ![_params boolForKey:@"perf_menu_animation" with3GEnabled:connected_via_3g];
|
||||
settings->DisableThemes = ![_params boolForKey:@"perf_windows_themes" with3GEnabled:connected_via_3g];
|
||||
settings->AllowFontSmoothing = [_params boolForKey:@"perf_font_smoothing" with3GEnabled:connected_via_3g];
|
||||
settings->AllowDesktopComposition = [_params boolForKey:@"perf_desktop_composition" with3GEnabled:connected_via_3g];
|
||||
|
||||
settings->PerformanceFlags = PERF_FLAG_NONE;
|
||||
if (settings->DisableWallpaper)
|
||||
settings->PerformanceFlags |= PERF_DISABLE_WALLPAPER;
|
||||
if (settings->DisableFullWindowDrag)
|
||||
settings->PerformanceFlags |= PERF_DISABLE_FULLWINDOWDRAG;
|
||||
if (settings->DisableMenuAnims)
|
||||
settings->PerformanceFlags |= PERF_DISABLE_MENUANIMATIONS;
|
||||
if (settings->DisableThemes)
|
||||
settings->PerformanceFlags |= PERF_DISABLE_THEMING;
|
||||
if (settings->AllowFontSmoothing)
|
||||
settings->PerformanceFlags |= PERF_ENABLE_FONT_SMOOTHING;
|
||||
if (settings->AllowDesktopComposition)
|
||||
settings->PerformanceFlags |= PERF_ENABLE_DESKTOP_COMPOSITION;
|
||||
|
||||
if ([_params hasValueForKey:@"width"])
|
||||
settings->DesktopWidth = [_params intForKey:@"width"];
|
||||
if ([_params hasValueForKey:@"height"])
|
||||
settings->DesktopHeight = [_params intForKey:@"height"];
|
||||
|
||||
// security
|
||||
switch ([_params intForKey:@"security"])
|
||||
{
|
||||
case TSXProtocolSecurityNLA:
|
||||
settings->RdpSecurity = FALSE;
|
||||
settings->TlsSecurity = FALSE;
|
||||
settings->NlaSecurity = TRUE;
|
||||
settings->ExtSecurity = FALSE;
|
||||
break;
|
||||
|
||||
case TSXProtocolSecurityTLS:
|
||||
settings->RdpSecurity = FALSE;
|
||||
settings->TlsSecurity = TRUE;
|
||||
settings->NlaSecurity = FALSE;
|
||||
settings->ExtSecurity = FALSE;
|
||||
break;
|
||||
|
||||
case TSXProtocolSecurityRDP:
|
||||
settings->RdpSecurity = TRUE;
|
||||
settings->TlsSecurity = FALSE;
|
||||
settings->NlaSecurity = FALSE;
|
||||
settings->ExtSecurity = FALSE;
|
||||
settings->DisableEncryption = TRUE;
|
||||
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
|
||||
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Remote keyboard layout
|
||||
settings->KeyboardLayout = 0x409;
|
||||
|
||||
// Audio settings
|
||||
settings->AudioPlayback = FALSE;
|
||||
settings->AudioCapture = FALSE;
|
||||
|
||||
[self mfi]->session = self;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self setDelegate:nil];
|
||||
[_bookmark release];
|
||||
[_name release];
|
||||
[_params release];
|
||||
[_ui_request_completed release];
|
||||
|
||||
ios_freerdp_free(_freerdp);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (CGContextRef)bitmapContext
|
||||
{
|
||||
return [self mfi]->bitmap_context;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Connecting and disconnecting
|
||||
|
||||
- (void)connect
|
||||
{
|
||||
// Set Screen Size to automatic if widht or height are still 0
|
||||
rdpSettings* settings = _freerdp->settings;
|
||||
if (settings->DesktopWidth == 0 || settings->DesktopHeight == 0)
|
||||
{
|
||||
CGSize size = CGSizeZero;
|
||||
if ([[self delegate] respondsToSelector:@selector(sizeForFitScreenForSession:)])
|
||||
size = [[self delegate] sizeForFitScreenForSession:self];
|
||||
|
||||
if (!CGSizeEqualToSize(CGSizeZero, size))
|
||||
{
|
||||
[_params setInt:size.width forKey:@"width"];
|
||||
[_params setInt:size.height forKey:@"height"];
|
||||
settings->DesktopWidth = size.width;
|
||||
settings->DesktopHeight = size.height;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This is a hack to ensure connections to RDVH with 16bpp don't have an odd screen resolution width
|
||||
// Otherwise this could result in screen corruption ..
|
||||
if (settings->ColorDepth <= 16)
|
||||
settings->DesktopWidth &= (~1);
|
||||
|
||||
[self performSelectorInBackground:@selector(runSession) withObject:nil];
|
||||
}
|
||||
|
||||
- (void)disconnect
|
||||
{
|
||||
mfInfo* mfi = [self mfi];
|
||||
|
||||
ios_events_send(mfi, [NSDictionary dictionaryWithObject:@"disconnect" forKey:@"type"]);
|
||||
|
||||
if (mfi->connection_state == TSXConnectionConnecting)
|
||||
{
|
||||
mfi->unwanted = YES;
|
||||
[self sessionDidDisconnect];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (TSXConnectionState)connectionState
|
||||
{
|
||||
return [self mfi]->connection_state;
|
||||
}
|
||||
|
||||
// suspends the session
|
||||
-(void)suspend
|
||||
{
|
||||
if(!_suspended)
|
||||
{
|
||||
_suspended = YES;
|
||||
// instance->update->SuppressOutput(instance->context, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// resumes a previously suspended session
|
||||
-(void)resume
|
||||
{
|
||||
if(_suspended)
|
||||
{
|
||||
/* RECTANGLE_16 rec;
|
||||
rec.left = 0;
|
||||
rec.top = 0;
|
||||
rec.right = instance->settings->width;
|
||||
rec.bottom = instance->settings->height;
|
||||
*/
|
||||
_suspended = NO;
|
||||
// instance->update->SuppressOutput(instance->context, 1, &rec);
|
||||
// [delegate sessionScreenSettingsChanged:self];
|
||||
}
|
||||
}
|
||||
|
||||
// returns YES if the session is started
|
||||
-(BOOL)isSuspended
|
||||
{
|
||||
return _suspended;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Input events
|
||||
|
||||
- (void)sendInputEvent:(NSDictionary*)eventDescriptor
|
||||
{
|
||||
if ([self mfi]->connection_state == TSXConnectionConnected)
|
||||
ios_events_send([self mfi], eventDescriptor);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Server events (main thread)
|
||||
|
||||
- (void)setNeedsDisplayInRectAsValue:(NSValue*)rect_value
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(session:needsRedrawInRect:)])
|
||||
[[self delegate] session:self needsRedrawInRect:[rect_value CGRectValue]];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark interface functions
|
||||
|
||||
- (UIImage*)getScreenshotWithSize:(CGSize)size
|
||||
{
|
||||
NSAssert([self mfi]->bitmap_context != nil, @"Screenshot requested while having no valid RDP drawing context");
|
||||
|
||||
CGImageRef cgImage = CGBitmapContextCreateImage([self mfi]->bitmap_context);
|
||||
UIGraphicsBeginImageContext(size);
|
||||
|
||||
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, size.height);
|
||||
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0);
|
||||
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width, size.height), cgImage);
|
||||
|
||||
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
CGImageRelease(cgImage);
|
||||
|
||||
return viewImage;
|
||||
}
|
||||
|
||||
- (rdpSettings*)getSessionParams
|
||||
{
|
||||
return _freerdp->settings;
|
||||
}
|
||||
|
||||
- (NSString*)sessionName
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@implementation RDPSession (Private)
|
||||
|
||||
- (mfInfo*)mfi
|
||||
{
|
||||
return MFI_FROM_INSTANCE(_freerdp);
|
||||
}
|
||||
|
||||
// Blocks until rdp session finishes.
|
||||
- (void)runSession
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Run the session
|
||||
[self performSelectorOnMainThread:@selector(sessionWillConnect) withObject:nil waitUntilDone:YES];
|
||||
int result_code = ios_run_freerdp(_freerdp);
|
||||
[self mfi]->connection_state = TSXConnectionDisconnected;
|
||||
[self performSelectorOnMainThread:@selector(runSessionFinished:) withObject:[NSNumber numberWithInt:result_code] waitUntilDone:YES];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
// Main thread.
|
||||
- (void)runSessionFinished:(NSNumber*)result
|
||||
{
|
||||
int result_code = [result intValue];
|
||||
|
||||
switch (result_code)
|
||||
{
|
||||
case MF_EXIT_CONN_CANCELED:
|
||||
[self sessionDidDisconnect];
|
||||
break;
|
||||
case MF_EXIT_LOGON_TIMEOUT:
|
||||
case MF_EXIT_CONN_FAILED:
|
||||
[self sessionDidFailToConnect:result_code];
|
||||
break;
|
||||
case MF_EXIT_SUCCESS:
|
||||
default:
|
||||
[self sessionDidDisconnect];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Session management (main thread)
|
||||
|
||||
- (void)sessionWillConnect
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(sessionWillConnect:)])
|
||||
[[self delegate] sessionWillConnect:self];
|
||||
}
|
||||
|
||||
- (void)sessionDidConnect
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(sessionDidConnect:)])
|
||||
[[self delegate] sessionDidConnect:self];
|
||||
}
|
||||
|
||||
- (void)sessionDidFailToConnect:(int)reason
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:TSXSessionDidFailToConnectNotification object:self];
|
||||
|
||||
if ([[self delegate] respondsToSelector:@selector(session:didFailToConnect:)])
|
||||
[[self delegate] session:self didFailToConnect:reason];
|
||||
}
|
||||
|
||||
- (void)sessionDidDisconnect
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:TSXSessionDidDisconnectNotification object:self];
|
||||
|
||||
if ([[self delegate] respondsToSelector:@selector(sessionDidDisconnect:)])
|
||||
[[self delegate] sessionDidDisconnect:self];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextWillChange
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextWillChange:)])
|
||||
[[self delegate] sessionBitmapContextWillChange:self];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextDidChange
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextDidChange:)])
|
||||
[[self delegate] sessionBitmapContextDidChange:self];
|
||||
}
|
||||
|
||||
- (void)showGoProScreen
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(showGoProScreen:)])
|
||||
[[self delegate] showGoProScreen:self];
|
||||
}
|
||||
|
||||
- (void)sessionRequestsAuthenticationWithParams:(NSMutableDictionary*)params
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(session:requestsAuthenticationWithParams:)])
|
||||
[[self delegate] session:self requestsAuthenticationWithParams:params];
|
||||
}
|
||||
|
||||
- (void)sessionVerifyCertificateWithParams:(NSMutableDictionary*)params
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(session:verifyCertificateWithParams:)])
|
||||
[[self delegate] session:self verifyCertificateWithParams:params];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,365 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1296</int>
|
||||
<string key="IBDocument.SystemVersion">11D50b</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2182</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.32</string>
|
||||
<string key="IBDocument.HIToolboxVersion">568.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">1179</string>
|
||||
</object>
|
||||
<array key="IBDocument.IntegratedClassDependencies">
|
||||
<string>IBUITableView</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUISearchBar</string>
|
||||
<string>IBProxyObject</string>
|
||||
</array>
|
||||
<array key="IBDocument.PluginDependencies">
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</array>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="191373211">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<array class="NSMutableArray" key="NSSubviews">
|
||||
<object class="IBUITableView" id="589060229">
|
||||
<reference key="NSNextResponder" ref="191373211"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrame">{{0, 44}, {320, 416}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="72664573"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">10</int>
|
||||
<object class="NSImage" key="NSImage">
|
||||
<int key="NSImageFlags">549453824</int>
|
||||
<string key="NSSize">{512, 1}</string>
|
||||
<array class="NSMutableArray" key="NSReps">
|
||||
<array>
|
||||
<integer value="0"/>
|
||||
<object class="NSBitmapImageRep">
|
||||
<object class="NSData" key="NSTIFFRepresentation">
|
||||
<bytes key="NS.bytes">TU0AKgAACAjFzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/
|
||||
y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/
|
||||
xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/
|
||||
xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/
|
||||
xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/
|
||||
xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/
|
||||
xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/
|
||||
y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/
|
||||
y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/
|
||||
xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/
|
||||
xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/
|
||||
xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/
|
||||
xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/
|
||||
xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/
|
||||
y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/
|
||||
y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/
|
||||
xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/
|
||||
xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/
|
||||
xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/
|
||||
xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/
|
||||
xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/
|
||||
y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/
|
||||
y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/
|
||||
xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/
|
||||
xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/
|
||||
xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/
|
||||
xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/
|
||||
xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/
|
||||
y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/
|
||||
y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/
|
||||
xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/
|
||||
xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/
|
||||
xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/
|
||||
xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/
|
||||
xczS/8vS2P/L0tj/xczU/wANAQAAAwAAAAECAAAAAQEAAwAAAAEAAQAAAQIAAwAAAAQAAAiqAQMAAwAA
|
||||
AAEAAQAAAQYAAwAAAAEAAgAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEABAAAARYAAwAA
|
||||
AAEAAQAAARcABAAAAAEAAAgAARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAQAAAiyAAAAAAAI
|
||||
AAgACAAIAAEAAQABAAE</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
</array>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MCAwAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<string key="IBUIColorCocoaTouchKeyPath">groupTableViewBackgroundColor</string>
|
||||
</object>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<bool key="IBUIAlwaysBounceVertical">YES</bool>
|
||||
<int key="IBUIStyle">1</int>
|
||||
<int key="IBUISeparatorStyle">2</int>
|
||||
<int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
|
||||
<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
|
||||
<float key="IBUIRowHeight">44</float>
|
||||
<float key="IBUISectionHeaderHeight">10</float>
|
||||
<float key="IBUISectionFooterHeight">10</float>
|
||||
</object>
|
||||
<object class="IBUISearchBar" id="72664573">
|
||||
<reference key="NSNextResponder" ref="191373211"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrameSize">{320, 44}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<int key="IBUIContentMode">3</int>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="IBUITextInputTraits" key="IBTextInputTraits">
|
||||
<int key="IBUIAutocorrectionType">1</int>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="589060229"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<array class="NSMutableArray" key="connectionRecords">
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">tableView</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="589060229"/>
|
||||
</object>
|
||||
<int key="connectionID">6</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="191373211"/>
|
||||
</object>
|
||||
<int key="connectionID">7</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">searchBar</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="72664573"/>
|
||||
</object>
|
||||
<int key="connectionID">5</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="589060229"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">8</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">dataSource</string>
|
||||
<reference key="source" ref="589060229"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">9</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="72664573"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">10</int>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<array key="orderedObjects">
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<array key="object" id="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="191373211"/>
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="589060229"/>
|
||||
<reference ref="72664573"/>
|
||||
</array>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="589060229"/>
|
||||
<array class="NSMutableArray" key="children"/>
|
||||
<reference key="parent" ref="191373211"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="72664573"/>
|
||||
<reference key="parent" ref="191373211"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
<string key="-1.CustomClassName">BookmarkListController</string>
|
||||
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="-2.CustomClassName">UIResponder</string>
|
||||
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="3.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">10</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BookmarkListController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<dictionary class="NSMutableDictionary" key="outlets">
|
||||
<string key="bmTableCell">BookmarkTableCell</string>
|
||||
<string key="searchBar">UISearchBar</string>
|
||||
<string key="sessTableCell">SessionsTableCell</string>
|
||||
<string key="tableView">UITableView</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<object class="IBToOneOutletInfo" key="bmTableCell">
|
||||
<string key="name">bmTableCell</string>
|
||||
<string key="candidateClassName">BookmarkTableCell</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="searchBar">
|
||||
<string key="name">searchBar</string>
|
||||
<string key="candidateClassName">UISearchBar</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="sessTableCell">
|
||||
<string key="name">sessTableCell</string>
|
||||
<string key="candidateClassName">SessionsTableCell</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="tableView">
|
||||
<string key="name">tableView</string>
|
||||
<string key="candidateClassName">UITableView</string>
|
||||
</object>
|
||||
</dictionary>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BookmarkListController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BookmarkTableCell</string>
|
||||
<string key="superclassName">UITableViewCell</string>
|
||||
<dictionary class="NSMutableDictionary" key="outlets">
|
||||
<string key="_connection_state_icon">UIImageView</string>
|
||||
<string key="_sub_title">UILabel</string>
|
||||
<string key="_title">UILabel</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<object class="IBToOneOutletInfo" key="_connection_state_icon">
|
||||
<string key="name">_connection_state_icon</string>
|
||||
<string key="candidateClassName">UIImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_sub_title">
|
||||
<string key="name">_sub_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_title">
|
||||
<string key="name">_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
</dictionary>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BookmarkTableCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">SessionsTableCell</string>
|
||||
<string key="superclassName">UITableViewCell</string>
|
||||
<dictionary class="NSMutableDictionary" key="outlets">
|
||||
<string key="_disconnect_button">UIButton</string>
|
||||
<string key="_screenshot">UIImageView</string>
|
||||
<string key="_server">UILabel</string>
|
||||
<string key="_title">UILabel</string>
|
||||
<string key="_username">UILabel</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<object class="IBToOneOutletInfo" key="_disconnect_button">
|
||||
<string key="name">_disconnect_button</string>
|
||||
<string key="candidateClassName">UIButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_screenshot">
|
||||
<string key="name">_screenshot</string>
|
||||
<string key="candidateClassName">UIImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_server">
|
||||
<string key="name">_server</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_title">
|
||||
<string key="name">_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo" key="_username">
|
||||
<string key="name">_username</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
</dictionary>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/SessionsTableCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1296" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">1179</string>
|
||||
</data>
|
||||
</archive>
|
|
@ -0,0 +1,428 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1296</int>
|
||||
<string key="IBDocument.SystemVersion">11D50b</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2182</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.32</string>
|
||||
<string key="IBDocument.HIToolboxVersion">568.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">1179</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUILabel</string>
|
||||
<string>IBUITableViewCell</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
</object>
|
||||
<object class="IBUITableViewCell" id="581303870">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUIView" id="806623018">
|
||||
<reference key="NSNextResponder" ref="581303870"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUILabel" id="915789886">
|
||||
<reference key="NSNextResponder" ref="806623018"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{20, 2}, {267, 21}}</string>
|
||||
<reference key="NSSuperview" ref="806623018"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="74446343"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<int key="IBUIContentMode">7</int>
|
||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<string key="IBUIText">Label</string>
|
||||
<object class="NSColor" key="IBUITextColor" id="782525937">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MCAwIDAAA</bytes>
|
||||
</object>
|
||||
<object class="NSColor" key="IBUIHighlightedColor" id="549211185">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
<int key="IBUIBaselineAdjustment">0</int>
|
||||
<float key="IBUIMinimumFontSize">10</float>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription">
|
||||
<int key="type">2</int>
|
||||
<double key="pointSize">18</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont">
|
||||
<string key="NSName">Helvetica-Bold</string>
|
||||
<double key="NSSize">18</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUILabel" id="74446343">
|
||||
<reference key="NSNextResponder" ref="806623018"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{20, 20}, {267, 21}}</string>
|
||||
<reference key="NSSuperview" ref="806623018"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<int key="IBUIContentMode">7</int>
|
||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<string key="IBUIText">Label</string>
|
||||
<reference key="IBUITextColor" ref="782525937"/>
|
||||
<reference key="IBUIHighlightedColor" ref="549211185"/>
|
||||
<int key="IBUIBaselineAdjustment">0</int>
|
||||
<float key="IBUIMinimumFontSize">10</float>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription">
|
||||
<int key="type">1</int>
|
||||
<double key="pointSize">14</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont">
|
||||
<string key="NSName">Helvetica</string>
|
||||
<double key="NSSize">14</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{287, 43}</string>
|
||||
<reference key="NSSuperview" ref="581303870"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="915789886"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:11</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MCAwAA</bytes>
|
||||
</object>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<int key="IBUIContentMode">4</int>
|
||||
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{320, 44}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="806623018"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBUIAccessoryType">2</int>
|
||||
<reference key="IBUIContentView" ref="806623018"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">bmTableCell</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="581303870"/>
|
||||
</object>
|
||||
<int key="connectionID">23</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_sub_title</string>
|
||||
<reference key="source" ref="581303870"/>
|
||||
<reference key="destination" ref="74446343"/>
|
||||
</object>
|
||||
<int key="connectionID">21</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_title</string>
|
||||
<reference key="source" ref="581303870"/>
|
||||
<reference key="destination" ref="915789886"/>
|
||||
</object>
|
||||
<int key="connectionID">22</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">18</int>
|
||||
<reference key="object" ref="581303870"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="915789886"/>
|
||||
<reference ref="74446343"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">19</int>
|
||||
<reference key="object" ref="915789886"/>
|
||||
<reference key="parent" ref="581303870"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">20</int>
|
||||
<reference key="object" ref="74446343"/>
|
||||
<reference key="parent" ref="581303870"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>18.CustomClassName</string>
|
||||
<string>18.IBPluginDependency</string>
|
||||
<string>19.IBPluginDependency</string>
|
||||
<string>20.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>BookmarkListController</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>BookmarkTableCell</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">23</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BookmarkListController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>bmTableCell</string>
|
||||
<string>searchBar</string>
|
||||
<string>sessTableCell</string>
|
||||
<string>tableView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>BookmarkTableCell</string>
|
||||
<string>UISearchBar</string>
|
||||
<string>SessionTableCell</string>
|
||||
<string>UITableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>bmTableCell</string>
|
||||
<string>searchBar</string>
|
||||
<string>sessTableCell</string>
|
||||
<string>tableView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">bmTableCell</string>
|
||||
<string key="candidateClassName">BookmarkTableCell</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">searchBar</string>
|
||||
<string key="candidateClassName">UISearchBar</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">sessTableCell</string>
|
||||
<string key="candidateClassName">SessionTableCell</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">tableView</string>
|
||||
<string key="candidateClassName">UITableView</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BookmarkListController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BookmarkTableCell</string>
|
||||
<string key="superclassName">UITableViewCell</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>_connection_state_icon</string>
|
||||
<string>_sub_title</string>
|
||||
<string>_title</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>UIImageView</string>
|
||||
<string>UILabel</string>
|
||||
<string>UILabel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>_connection_state_icon</string>
|
||||
<string>_sub_title</string>
|
||||
<string>_title</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_connection_state_icon</string>
|
||||
<string key="candidateClassName">UIImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_sub_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BookmarkTableCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">SessionTableCell</string>
|
||||
<string key="superclassName">UITableViewCell</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>_disconnect_button</string>
|
||||
<string>_screenshot</string>
|
||||
<string>_server</string>
|
||||
<string>_title</string>
|
||||
<string>_username</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>UIButton</string>
|
||||
<string>UIImageView</string>
|
||||
<string>UILabel</string>
|
||||
<string>UILabel</string>
|
||||
<string>UILabel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>_disconnect_button</string>
|
||||
<string>_screenshot</string>
|
||||
<string>_server</string>
|
||||
<string>_title</string>
|
||||
<string>_username</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_disconnect_button</string>
|
||||
<string key="candidateClassName">UIButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_screenshot</string>
|
||||
<string key="candidateClassName">UIImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_server</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_title</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">_username</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/SessionTableCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1296" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3100" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">1179</string>
|
||||
</data>
|
||||
</archive>
|
|
@ -0,0 +1,481 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1296</int>
|
||||
<string key="IBDocument.SystemVersion">11D50b</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2182</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.32</string>
|
||||
<string key="IBDocument.HIToolboxVersion">568.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">1179</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBUITextField</string>
|
||||
<string>IBUILabel</string>
|
||||
<string>IBUIButton</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUIScrollView</string>
|
||||
<string>IBProxyObject</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="234977634">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUIScrollView" id="76355032">
|
||||
<reference key="NSNextResponder" ref="234977634"/>
|
||||
<int key="NSvFlags">279</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUITextField" id="502350293">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{15, 112}, {210, 31}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<reference key="NSNextKeyView" ref="407758879"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<string key="IBUIText"/>
|
||||
<int key="IBUIBorderStyle">3</int>
|
||||
<string key="IBUIPlaceholder">Username</string>
|
||||
<object class="NSColor" key="IBUITextColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace" id="1055564775">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
|
||||
<float key="IBUIMinimumFontSize">17</float>
|
||||
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<int key="IBUIClearButtonMode">3</int>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription" id="72634085">
|
||||
<int key="type">1</int>
|
||||
<double key="pointSize">12</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont" id="168483421">
|
||||
<string key="NSName">Helvetica</string>
|
||||
<double key="NSSize">12</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUITextField" id="407758879">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{15, 161}, {210, 31}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<reference key="NSNextKeyView" ref="316210701"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<string key="IBUIText"/>
|
||||
<int key="IBUIBorderStyle">3</int>
|
||||
<string key="IBUIPlaceholder">Password</string>
|
||||
<object class="NSColor" key="IBUITextColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
<reference key="NSCustomColorSpace" ref="1055564775"/>
|
||||
</object>
|
||||
<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
|
||||
<float key="IBUIMinimumFontSize">17</float>
|
||||
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
|
||||
<bool key="IBUISecureTextEntry">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<int key="IBUIClearButtonMode">3</int>
|
||||
<reference key="IBUIFontDescription" ref="72634085"/>
|
||||
<reference key="IBUIFont" ref="168483421"/>
|
||||
</object>
|
||||
<object class="IBUITextField" id="316210701">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{15, 210}, {210, 31}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<reference key="NSNextKeyView" ref="266626143"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<string key="IBUIText"/>
|
||||
<int key="IBUIBorderStyle">3</int>
|
||||
<string key="IBUIPlaceholder">Domain</string>
|
||||
<object class="NSColor" key="IBUITextColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
<reference key="NSCustomColorSpace" ref="1055564775"/>
|
||||
</object>
|
||||
<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
|
||||
<float key="IBUIMinimumFontSize">17</float>
|
||||
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<int key="IBUIClearButtonMode">3</int>
|
||||
<reference key="IBUIFontDescription" ref="72634085"/>
|
||||
<reference key="IBUIFont" ref="168483421"/>
|
||||
</object>
|
||||
<object class="IBUIButton" id="67582393">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">291</int>
|
||||
<string key="NSFrame">{{130, 263}, {95, 37}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<int key="IBUIButtonType">1</int>
|
||||
<string key="IBUINormalTitle">Cancel</string>
|
||||
<object class="NSColor" key="IBUIHighlightedTitleColor" id="484131582">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
<object class="NSColor" key="IBUINormalTitleColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
|
||||
</object>
|
||||
<object class="NSColor" key="IBUINormalTitleShadowColor" id="210891822">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MC41AA</bytes>
|
||||
</object>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription" id="223796057">
|
||||
<string key="name">Helvetica-Bold</string>
|
||||
<string key="family">Helvetica</string>
|
||||
<int key="traits">2</int>
|
||||
<double key="pointSize">15</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont" id="1043513320">
|
||||
<string key="NSName">Helvetica-Bold</string>
|
||||
<double key="NSSize">15</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUIButton" id="266626143">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">294</int>
|
||||
<string key="NSFrame">{{15, 263}, {95, 37}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<reference key="NSNextKeyView" ref="67582393"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
<int key="IBUIButtonType">1</int>
|
||||
<string key="IBUINormalTitle">Login</string>
|
||||
<reference key="IBUIHighlightedTitleColor" ref="484131582"/>
|
||||
<object class="NSColor" key="IBUINormalTitleColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
|
||||
</object>
|
||||
<reference key="IBUINormalTitleShadowColor" ref="210891822"/>
|
||||
<reference key="IBUIFontDescription" ref="223796057"/>
|
||||
<reference key="IBUIFont" ref="1043513320"/>
|
||||
</object>
|
||||
<object class="IBUILabel" id="876100682">
|
||||
<reference key="NSNextResponder" ref="76355032"/>
|
||||
<int key="NSvFlags">290</int>
|
||||
<string key="NSFrame">{{15, 20}, {210, 71}}</string>
|
||||
<reference key="NSSuperview" ref="76355032"/>
|
||||
<reference key="NSNextKeyView" ref="502350293"/>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<int key="IBUIContentMode">7</int>
|
||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<string key="IBUIText">Please provide the missing user information in order to proceed and login.</string>
|
||||
<object class="NSColor" key="IBUITextColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MCAwIDAAA</bytes>
|
||||
</object>
|
||||
<nil key="IBUIHighlightedColor"/>
|
||||
<int key="IBUIBaselineAdjustment">1</int>
|
||||
<float key="IBUIMinimumFontSize">10</float>
|
||||
<int key="IBUINumberOfLines">3</int>
|
||||
<int key="IBUILineBreakMode">0</int>
|
||||
<object class="IBUIFontDescription" key="IBUIFontDescription">
|
||||
<int key="type">1</int>
|
||||
<double key="pointSize">17</double>
|
||||
</object>
|
||||
<object class="NSFont" key="IBUIFont">
|
||||
<string key="NSName">Helvetica</string>
|
||||
<double key="NSSize">17</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{240, 320}</string>
|
||||
<reference key="NSSuperview" ref="234977634"/>
|
||||
<reference key="NSNextKeyView" ref="876100682"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{240, 320}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSNextKeyView" ref="76355032"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<reference key="NSCustomColorSpace" ref="1055564775"/>
|
||||
</object>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="234977634"/>
|
||||
</object>
|
||||
<int key="connectionID">41</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_scroll_view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="76355032"/>
|
||||
</object>
|
||||
<int key="connectionID">42</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_textfield_username</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="502350293"/>
|
||||
</object>
|
||||
<int key="connectionID">34</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_textfield_password</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="407758879"/>
|
||||
</object>
|
||||
<int key="connectionID">33</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_textfield_domain</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="316210701"/>
|
||||
</object>
|
||||
<int key="connectionID">32</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_btn_cancel</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="67582393"/>
|
||||
</object>
|
||||
<int key="connectionID">30</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_btn_login</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="266626143"/>
|
||||
</object>
|
||||
<int key="connectionID">31</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">_lbl_message</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="876100682"/>
|
||||
</object>
|
||||
<int key="connectionID">43</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">cancelPressed:</string>
|
||||
<reference key="source" ref="67582393"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">36</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">loginPressed:</string>
|
||||
<reference key="source" ref="266626143"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">37</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">40</int>
|
||||
<reference key="object" ref="234977634"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="76355032"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">38</int>
|
||||
<reference key="object" ref="76355032"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="876100682"/>
|
||||
<reference ref="266626143"/>
|
||||
<reference ref="67582393"/>
|
||||
<reference ref="502350293"/>
|
||||
<reference ref="316210701"/>
|
||||
<reference ref="407758879"/>
|
||||
</object>
|
||||
<reference key="parent" ref="234977634"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="502350293"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="407758879"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">7</int>
|
||||
<reference key="object" ref="316210701"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">10</int>
|
||||
<reference key="object" ref="67582393"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">20</int>
|
||||
<reference key="object" ref="266626143"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">11</int>
|
||||
<reference key="object" ref="876100682"/>
|
||||
<reference key="parent" ref="76355032"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBAttributePlaceholdersKey</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>10.IBPluginDependency</string>
|
||||
<string>11.IBPluginDependency</string>
|
||||
<string>20.IBPluginDependency</string>
|
||||
<string>3.IBPluginDependency</string>
|
||||
<string>38.IBPluginDependency</string>
|
||||
<string>40.IBPluginDependency</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>7.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>CredentialsInputController</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<object class="NSMutableDictionary">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">43</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1296" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3100" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">1179</string>
|
||||
</data>
|
||||
</archive>
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue