Skip to content

Commit

Permalink
Merge branch 'master' into refactor_useQCommandLineParser
Browse files Browse the repository at this point in the history
  • Loading branch information
AHeimberger authored Mar 17, 2022
2 parents 3dff96b + 9957287 commit 6790090
Show file tree
Hide file tree
Showing 102 changed files with 2,355 additions and 1,630 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "src/3rdparty/libcrashreporter-qt"]
path = src/3rdparty/libcrashreporter-qt
url = git://github.com/dschmidt/libcrashreporter-qt.git
url = git@github.com:dschmidt/libcrashreporter-qt.git
8 changes: 4 additions & 4 deletions .tx/nextcloud.client-desktop/de_translation
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Icon=@APPLICATION_EXECUTABLE@


# Translations
Icon[de_DE]=@APPLICATION_ICON_NAME@
Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
GenericName[de_DE]=Ordnersynchronisierung
Icon[de]=@APPLICATION_ICON_NAME@
Name[de]=@APPLICATION_NAME@ Desktop
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
GenericName[de]=Ordner-Synchronisation
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@

#import <Cocoa/Cocoa.h>
#import <FinderSync/FinderSync.h>
#import "SyncClientProxy.h"
#import "SyncClient.h"
#import "LineProcessor.h"
#import "LocalSocketClient.h"

@interface FinderSync : FIFinderSync <SyncClientProxyDelegate>
@interface FinderSync : FIFinderSync <SyncClientDelegate>
{
SyncClientProxy *_syncClientProxy;
NSMutableSet *_registeredDirectories;
NSString *_shareMenuTitle;
NSMutableDictionary *_strings;
NSMutableArray *_menuItems;
NSMutableSet *_registeredDirectories;
NSString *_shareMenuTitle;
NSMutableDictionary *_strings;
NSMutableArray *_menuItems;
NSCondition *_menuIsComplete;
}

@property LineProcessor *lineProcessor;
@property LocalSocketClient *localSocketClient;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,32 @@ - (instancetype)init
// - Be prefixed with the code signing Team ID
// - Then infixed with the sandbox App Group
// - The App Group itself must be a prefix of (or equal to) the application bundle identifier
// We end up in the official signed client with: 9B5WD74GWJ.com.owncloud.desktopclient.socketApi
// We end up in the official signed client with: 9B5WD74GWJ.com.owncloud.desktopclient.socket
// With ad-hoc signing (the '-' signing identity) we must drop the Team ID.
// When the code isn't sandboxed (e.g. the OC client or the legacy overlay icon extension)
// the OS doesn't seem to put any restriction on the port name, so we just follow what
// the sandboxed App Extension needs.
// https://developer.apple.com/library/mac/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24
NSString *serverName = [socketApiPrefix stringByAppendingString:@".socketApi"];
//NSLog(@"FinderSync serverName %@", serverName);

_syncClientProxy = [[SyncClientProxy alloc] initWithDelegate:self serverName:serverName];
_registeredDirectories = [[NSMutableSet alloc] init];
_strings = [[NSMutableDictionary alloc] init];

[_syncClientProxy start];
return self;

NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:socketApiPrefix];
NSURL *socketPath = [container URLByAppendingPathComponent:@".socket" isDirectory:NO];

NSLog(@"Socket path: %@", socketPath.path);

if (socketPath.path) {
self.lineProcessor = [[LineProcessor alloc] initWithDelegate:self];
self.localSocketClient = [[LocalSocketClient alloc] init:socketPath.path
lineProcessor:self.lineProcessor];
[self.localSocketClient start];
} else {
NSLog(@"No socket path. Not initiating local socket client.");
self.localSocketClient = nil;
}
_registeredDirectories = [[NSMutableSet alloc] init];
_strings = [[NSMutableDictionary alloc] init];
_menuIsComplete = [[NSCondition alloc] init];

return self;
}

#pragma mark - Primary Finder Sync protocol methods
Expand All @@ -76,7 +87,7 @@ - (void)requestBadgeIdentifierForURL:(NSURL *)url
}

NSString* normalizedPath = [[url path] decomposedStringWithCanonicalMapping];
[_syncClientProxy askForIcon:normalizedPath isDirectory:isDir];
[self.localSocketClient askForIcon:normalizedPath isDirectory:isDir];
}

#pragma mark - Menu and toolbar item support
Expand All @@ -95,8 +106,19 @@ - (NSString*) selectedPathsSeparatedByRecordSeparator
return string;
}

- (void)waitForMenuToArrive
{
[self->_menuIsComplete lock];
[self->_menuIsComplete wait];
[self->_menuIsComplete unlock];
}

- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu
{
if(![self.localSocketClient isConnected]) {
return nil;
}

FIFinderSyncController *syncController = [FIFinderSyncController defaultController];
NSMutableSet *rootPaths = [[NSMutableSet alloc] init];
[syncController.directoryURLs enumerateObjectsUsingBlock: ^(id obj, BOOL *stop) {
Expand All @@ -116,8 +138,11 @@ - (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu
}];

NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
// calling this IPC calls us back from client with several MENU_ITEM entries and then our askOnSocket returns again
[_syncClientProxy askOnSocket:paths query:@"GET_MENU_ITEMS"];
[self.localSocketClient askOnSocket:paths query:@"GET_MENU_ITEMS"];

// Since the LocalSocketClient communicates asynchronously. wait here until the menu
// is delivered by another thread
[self waitForMenuToArrive];

id contextMenuTitle = [_strings objectForKey:@"CONTEXT_MENU_TITLE"];
if (contextMenuTitle && !onlyRootsSelected) {
Expand Down Expand Up @@ -151,7 +176,7 @@ - (void)subMenuActionClicked:(id)sender {
long idx = [(NSMenuItem*)sender tag];
NSString *command = [[_menuItems objectAtIndex:idx] valueForKey:@"command"];
NSString *paths = [self selectedPathsSeparatedByRecordSeparator];
[_syncClientProxy askOnSocket:paths query:command];
[self.localSocketClient askOnSocket:paths query:command];
}

#pragma mark - SyncClientProxyDelegate implementation
Expand All @@ -164,6 +189,7 @@ - (void)setResultForPath:(NSString*)path result:(NSString*)result

- (void)reFetchFileNameCacheForPath:(NSString*)path
{

}

- (void)registerPath:(NSString*)path
Expand All @@ -189,9 +215,16 @@ - (void)resetMenuItems
_menuItems = [[NSMutableArray alloc] init];
}
- (void)addMenuItem:(NSDictionary *)item {
NSLog(@"Adding menu item.");
[_menuItems addObject:item];
}

- (void)menuHasCompleted
{
NSLog(@"Emitting menu is complete signal now.");
[self->_menuIsComplete signal];
}

- (void)connectionDidDie
{
[_strings removeAllObjects];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#import "SyncClient.h"

#ifndef LineProcessor_h
#define LineProcessor_h

/// This class is in charge of dispatching all work that must be done on the UI side of the extension.
/// Tasks are dispatched on the main UI thread for this reason.
///
/// These tasks are parsed from byte data (UTF9 strings) acquired from the socket; look at the
/// LocalSocketClient for more detail on how data is read from and written to the socket.

@interface LineProcessor : NSObject
@property(nonatomic, weak)id<SyncClientDelegate> delegate;

- (instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate;
- (void)process:(NSString*)line;

@end
#endif /* LineProcessor_h */
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#import <Foundation/Foundation.h>
#import "LineProcessor.h"

@implementation LineProcessor

-(instancetype)initWithDelegate:(id<SyncClientDelegate>)delegate
{
NSLog(@"Init line processor with delegate.");
self.delegate = delegate;
return self;
}

-(void)process:(NSString*)line
{
NSLog(@"Processing line: %@", line);
NSArray *split = [line componentsSeparatedByString:@":"];
NSString *command = [split objectAtIndex:0];

NSLog(@"Command: %@", command);

if([command isEqualToString:@"STATUS"]) {
NSString *result = [split objectAtIndex:1];
NSArray *pathSplit = [split subarrayWithRange:NSMakeRange(2, [split count] - 2)]; // Get everything after location 2
NSString *path = [pathSplit componentsJoinedByString:@":"];

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Setting result %@ for path %@", result, path);
[self.delegate setResultForPath:path result:result];
});
} else if([command isEqualToString:@"UPDATE_VIEW"]) {
NSString *path = [split objectAtIndex:1];

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Re-fetching filename cache for path %@", path);
[self.delegate reFetchFileNameCacheForPath:path];
});
} else if([command isEqualToString:@"REGISTER_PATH"]) {
NSString *path = [split objectAtIndex:1];

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Registering path %@", path);
[self.delegate registerPath:path];
});
} else if([command isEqualToString:@"UNREGISTER_PATH"]) {
NSString *path = [split objectAtIndex:1];

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Unregistering path %@", path);
[self.delegate unregisterPath:path];
});
} else if([command isEqualToString:@"GET_STRINGS"]) {
// BEGIN and END messages, do nothing.
return;
} else if([command isEqualToString:@"STRING"]) {
NSString *key = [split objectAtIndex:1];
NSString *value = [split objectAtIndex:2];

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Setting string %@ to value %@", key, value);
[self.delegate setString:key value:value];
});
} else if([command isEqualToString:@"GET_MENU_ITEMS"]) {
if([[split objectAtIndex:1] isEqualToString:@"BEGIN"]) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Resetting menu items.");
[self.delegate resetMenuItems];
});
} else {
NSLog(@"Emitting menu has completed signal.");
[self.delegate menuHasCompleted];
}
} else if([command isEqualToString:@"MENU_ITEM"]) {
NSDictionary *item = @{@"command": [split objectAtIndex:1], @"flags": [split objectAtIndex:2], @"text": [split objectAtIndex:3]};

dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Adding menu item with command %@, flags %@, and text %@", [split objectAtIndex:1], [split objectAtIndex:2], [split objectAtIndex:3]);
[self.delegate addMenuItem:item];
});
} else {
// LOG UNKOWN COMMAND
NSLog(@"Unkown command: %@", command);
}
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#import "LineProcessor.h"

#ifndef LocalSocketClient_h
#define LocalSocketClient_h
#define BUF_SIZE 4096

/// Class handling asynchronous communication with a server over a local UNIX socket.
///
/// The implementation uses a `DispatchQueue` and `DispatchSource`s to handle asynchronous communication and thread
/// safety. The delegate that handles the line-decoding is **not invoked on the UI thread**, but the (random) thread associated
/// with the `DispatchQueue`.
///
/// If any UI work needs to be done, the `LineProcessor` class dispatches this work on the main queue (so the UI thread) itself.
///
/// Other than the `init(withSocketPath:, lineProcessor)` and the `start()` method, all work is done "on the dispatch
/// queue". The `localSocketQueue` is a serial dispatch queue (so a maximum of 1, and only 1, task is run at any
/// moment), which guarantees safe access to instance variables. Both `askOnSocket(_:, query:)` and
/// `askForIcon(_:, isDirectory:)` will internally dispatch the work on the `DispatchQueue`.
///
/// Sending and receiving data to and from the socket, is handled by two `DispatchSource`s. These will run an event
/// handler when data can be read from resp. written to the socket. These handlers will also be run on the
/// `DispatchQueue`.

@interface LocalSocketClient : NSObject

@property NSString* socketPath;
@property LineProcessor* lineProcessor;
@property int sock;
@property dispatch_queue_t localSocketQueue;
@property dispatch_source_t readSource;
@property dispatch_source_t writeSource;
@property NSMutableData* inBuffer;
@property NSMutableData* outBuffer;

- (instancetype)init:(NSString*)socketPath lineProcessor:(LineProcessor*)lineProcessor;
- (BOOL)isConnected;
- (void)start;
- (void)restart;
- (void)closeConnection;
- (NSString*)strErr;
- (void)askOnSocket:(NSString*)path query:(NSString*)verb;
- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDirectory;
- (void)readFromSocket;
- (void)writeToSocket;
- (void)processInBuffer;

@end
#endif /* LocalSocketClient_h */
Loading

0 comments on commit 6790090

Please sign in to comment.