AppDelegate.m 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705
  1. //
  2. // AppDelegate.m
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 04/09/14.
  6. // Copyright (c) 2014 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. #import "AppDelegate.h"
  24. #import "CCGraphics.h"
  25. #import "CCSynchronize.h"
  26. #import "CCMain.h"
  27. #import "NCBridgeSwift.h"
  28. #import "NCAutoUpload.h"
  29. #import "NCPushNotificationEncryption.h"
  30. #import <QuartzCore/QuartzCore.h>
  31. @import Sentry;
  32. @class NCViewerRichdocument;
  33. @interface AppDelegate() <TOPasscodeViewControllerDelegate>
  34. @end
  35. @implementation AppDelegate
  36. + (void)initialize
  37. {
  38. [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": [CCUtility getUserAgent]}];
  39. }
  40. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  41. {
  42. if (![CCUtility getDisableCrashservice] && NCBrandOptions.sharedInstance.disable_crash_service == false) {
  43. [SentrySDK startWithOptions: @{
  44. @"dsn": @"https://42eaf570ec2646b1a564a4c4bfc8c279@o394108.ingest.sentry.io/5243836",
  45. @"debug": @(YES),
  46. @"enableAutoSessionTracking": @(YES)
  47. /* PRIVACY : https://github.com/getsentry/sentry-cocoa
  48. By default, we don’t apply the user identification provided to the SDK via the API. Instead, we use
  49. the installation ID generated with the first use of the application. The ID doesn’t contain any
  50. private or public data of your users or any public or shared data of their device.
  51. */
  52. }];
  53. }
  54. [CCUtility createDirectoryStandard];
  55. [CCUtility emptyTemporaryDirectory];
  56. // Networking
  57. [[NCCommunicationCommon shared] setupWithDelegate:[NCNetworking shared]];
  58. [[NCCommunicationCommon shared] setupWithUserAgent:[CCUtility getUserAgent] capabilitiesGroup:[NCBrandOptions sharedInstance].capabilitiesGroups];
  59. // Verify upgrade
  60. if ([self upgrade]) {
  61. // Set account, if no exists clear all
  62. tableAccount *tableAccount = [[NCManageDatabase sharedInstance] getAccountActive];
  63. if (tableAccount == nil) {
  64. // remove all the keys Chain
  65. [CCUtility deleteAllChainStore];
  66. // remove all the App group key
  67. [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
  68. } else {
  69. [self settingActiveAccount:tableAccount.account activeUrl:tableAccount.url activeUser:tableAccount.user activeUserID:tableAccount.userID activePassword:[CCUtility getPassword:tableAccount.account]];
  70. }
  71. }
  72. // UserDefaults
  73. self.ncUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:[NCBrandOptions sharedInstance].capabilitiesGroups];
  74. // Background Fetch
  75. [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
  76. self.listProgressMetadata = [NSMutableDictionary new];
  77. self.listMainVC = [NSMutableDictionary new];
  78. self.arrayDeleteMetadata = [NSMutableArray new];
  79. self.arrayMoveMetadata = [NSMutableArray new];
  80. self.arrayMoveServerUrlTo = [NSMutableArray new];
  81. self.arrayCopyMetadata = [NSMutableArray new];
  82. self.arrayCopyServerUrlTo = [NSMutableArray new];
  83. // Push Notification
  84. [application registerForRemoteNotifications];
  85. // Display notification
  86. [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  87. UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
  88. [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { }];
  89. //AV Session
  90. [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:nil];
  91. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  92. // ProgressView Detail
  93. self.progressViewDetail = [[UIProgressView alloc] initWithProgressViewStyle: UIProgressViewStyleBar];
  94. // Quick Actions
  95. if([[UIApplicationShortcutItem class] respondsToSelector:@selector(new)]) {
  96. [self configDynamicShortcutItems];
  97. UIApplicationShortcutItem *shortcutItem = [launchOptions objectForKeyedSubscript:UIApplicationLaunchOptionsShortcutItemKey];
  98. if (shortcutItem)
  99. [self handleShortCutItem:shortcutItem];
  100. }
  101. // Start Timer
  102. self.timerProcessAutoUpload = [NSTimer scheduledTimerWithTimeInterval:k_timerProcessAutoUpload target:self selector:@selector(loadAutoUpload) userInfo:nil repeats:YES];
  103. self.timerUpdateApplicationIconBadgeNumber = [NSTimer scheduledTimerWithTimeInterval:k_timerUpdateApplicationIconBadgeNumber target:self selector:@selector(updateApplicationIconBadgeNumber) userInfo:nil repeats:YES];
  104. [self startTimerErrorNetworking];
  105. // Store review
  106. if ([[NCUtility sharedInstance] isSimulatorOrTestFlight] == false) {
  107. NCStoreReview *review = [NCStoreReview new];
  108. [review incrementAppRuns];
  109. [review showStoreReview];
  110. }
  111. // Detect Dark mode
  112. if (@available(iOS 13.0, *)) {
  113. if ([CCUtility getDarkModeDetect]) {
  114. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  115. [CCUtility setDarkMode:YES];
  116. } else {
  117. [CCUtility setDarkMode:NO];
  118. }
  119. }
  120. }
  121. if ([NCBrandOptions sharedInstance].disable_intro) {
  122. [CCUtility setIntro:YES];
  123. if (self.activeAccount.length == 0) {
  124. [self openLoginView:nil selector:k_intro_login openLoginWeb:false];
  125. }
  126. } else {
  127. if ([CCUtility getIntro] == NO) {
  128. UIViewController *introViewController = [[UIStoryboard storyboardWithName:@"NCIntro" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
  129. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: introViewController];
  130. self.window.rootViewController = navController;
  131. [self.window makeKeyAndVisible];
  132. }
  133. }
  134. // init home
  135. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  136. // Observer
  137. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deleteFile:) name:k_notificationCenter_deleteFile object:nil];
  138. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moveFile:) name:k_notificationCenter_moveFile object:nil];
  139. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(copyFile:) name:k_notificationCenter_copyFile object:nil];
  140. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(uploadedFile:) name:k_notificationCenter_uploadedFile object:nil];
  141. // Passcode
  142. dispatch_async(dispatch_get_main_queue(), ^{
  143. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  144. });
  145. return YES;
  146. }
  147. //
  148. // L' applicazione si dimetterà dallo stato di attivo
  149. //
  150. - (void)applicationWillResignActive:(UIApplication *)application
  151. {
  152. // Test Maintenance
  153. if (self.activeAccount.length == 0 || self.maintenanceMode)
  154. return;
  155. [self updateApplicationIconBadgeNumber];
  156. }
  157. //
  158. // L' applicazione entrerà in primo piano (attivo solo dopo il background)
  159. //
  160. - (void)applicationWillEnterForeground:(UIApplication *)application
  161. {
  162. // Test Maintenance
  163. if (self.activeAccount.length == 0 || self.maintenanceMode)
  164. return;
  165. NSLog(@"[LOG] Request Passcode");
  166. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  167. NSLog(@"[LOG] Request Service Server Nextcloud");
  168. [[NCService shared] startRequestServicesServer];
  169. NSLog(@"[LOG] Initialize Auto upload");
  170. [[NCAutoUpload sharedInstance] initStateAutoUpload];
  171. NSLog(@"[LOG] Read active directory");
  172. [self.activeMain readFileReloadFolder];
  173. NSLog(@"[LOG] Required unsubscribing / subscribing");
  174. [self pushNotification];
  175. NSLog(@"[LOG] RichDocument");
  176. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_richdocumentGrabFocus object:nil];
  177. }
  178. //
  179. // L' applicazione entrerà in primo piano (attivo sempre)
  180. //
  181. - (void)applicationDidBecomeActive:(UIApplication *)application
  182. {
  183. // Test Maintenance
  184. if (self.activeAccount.length == 0 || self.maintenanceMode)
  185. return;
  186. // middelware ping
  187. if ([[NCBrandOptions sharedInstance] use_middlewarePing]) {
  188. NSLog(@"[LOG] Middleware Ping");
  189. [[NCService shared] middlewarePing];
  190. }
  191. // verify upload task lost
  192. [[NCNetworking shared] verifyDownloadRequestLost];
  193. [[NCNetworking shared] verifyUploadRequestLost];
  194. [self verifyUploadBackgroundLost];
  195. // verify delete Asset Local Identifiers in auto upload
  196. [[NCUtility sharedInstance] deleteAssetLocalIdentifiersWithAccount:self.activeAccount sessionSelector:selectorUploadAutoUpload];
  197. // Brand
  198. #if defined(HC)
  199. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountActive];
  200. if (account.hcIsTrial == true || account.hcTrialExpired == true || account.hcNextGroupExpirationGroupExpired == true) {
  201. HCTrial *vc = [[UIStoryboard storyboardWithName:@"HCTrial" bundle:nil] instantiateInitialViewController];
  202. vc.account = account;
  203. [self.window.rootViewController presentViewController:vc animated:YES completion:nil];
  204. }
  205. #endif
  206. }
  207. //
  208. // L' applicazione è entrata nello sfondo
  209. //
  210. - (void)applicationDidEnterBackground:(UIApplication *)application
  211. {
  212. NSLog(@"[LOG] Enter in Background");
  213. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_applicationDidEnterBackground object:nil];
  214. [self passcodeWithAutomaticallyPromptForBiometricValidation:false];
  215. }
  216. //
  217. // L'applicazione terminerà
  218. //
  219. - (void)applicationWillTerminate:(UIApplication *)application
  220. {
  221. NSLog(@"[LOG] bye bye, Nextcloud !");
  222. }
  223. #pragma --------------------------------------------------------------------------------------------
  224. #pragma mark ===== Login / checkErrorNetworking =====
  225. #pragma --------------------------------------------------------------------------------------------
  226. - (void)checkErrorNetworking
  227. {
  228. // test
  229. if (self.activeAccount.length == 0 || self.maintenanceMode)
  230. return;
  231. // check unauthorized server (401)
  232. if ([CCUtility getPassword:self.activeAccount].length == 0) {
  233. [self openLoginView:self.window.rootViewController selector:k_intro_login openLoginWeb:true];
  234. }
  235. // check certificate untrusted (-1202)
  236. if ([CCUtility getCertificateError:self.activeAccount]) {
  237. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_ssl_certificate_untrusted_", nil) message:NSLocalizedString(@"_connect_server_anyway_", nil) preferredStyle:UIAlertControllerStyleAlert];
  238. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_yes_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  239. [[NCNetworking shared] wrtiteCertificateWithDirectoryCertificate:[CCUtility getDirectoryCerificates]];
  240. [self startTimerErrorNetworking];
  241. }]];
  242. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_no_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  243. [self startTimerErrorNetworking];
  244. }]];
  245. [self.window.rootViewController presentViewController:alertController animated:YES completion:^{
  246. // Stop timer error network
  247. [self.timerErrorNetworking invalidate];
  248. }];
  249. }
  250. }
  251. - (void)openLoginView:(UIViewController *)viewController selector:(NSInteger)selector openLoginWeb:(BOOL)openLoginWeb
  252. {
  253. // use appConfig [MDM]
  254. if ([NCBrandOptions sharedInstance].use_configuration) {
  255. if (!(_appConfigView.isViewLoaded && _appConfigView.view.window)) {
  256. self.appConfigView = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCAppConfigView"];
  257. [self showLoginViewController:self.appConfigView forContext:viewController];
  258. }
  259. return;
  260. }
  261. // only for personalized LoginWeb [customer]
  262. if ([NCBrandOptions sharedInstance].use_login_web_personalized) {
  263. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  264. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  265. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] loginBaseUrl];
  266. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  267. }
  268. return;
  269. }
  270. // normal login
  271. if (selector == k_intro_signup) {
  272. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  273. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  274. if (selector == k_intro_signup) {
  275. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] linkloginPreferredProviders];
  276. } else {
  277. self.activeLoginWeb.urlBase = self.activeUrl;
  278. }
  279. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  280. }
  281. } else if ([NCBrandOptions sharedInstance].disable_intro && [NCBrandOptions sharedInstance].disable_request_login_url) {
  282. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  283. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] loginBaseUrl];
  284. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  285. } else if (openLoginWeb) {
  286. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  287. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  288. self.activeLoginWeb.urlBase = self.activeUrl;
  289. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  290. }
  291. } else {
  292. if (!(_activeLogin.isViewLoaded && _activeLogin.view.window)) {
  293. _activeLogin = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"CCLoginNextcloud"];
  294. [self showLoginViewController:_activeLogin forContext:viewController];
  295. }
  296. }
  297. }
  298. -(void)showLoginViewController:(UIViewController *)viewController forContext:(UIViewController *)contextViewController
  299. {
  300. if (contextViewController == NULL) {
  301. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
  302. navController.navigationBar.barStyle = UIBarStyleBlack;
  303. navController.navigationBar.tintColor = NCBrandColor.sharedInstance.customerText;
  304. navController.navigationBar.barTintColor = NCBrandColor.sharedInstance.customer;
  305. [navController.navigationBar setTranslucent:false];
  306. self.window.rootViewController = navController;
  307. [self.window makeKeyAndVisible];
  308. } else if ([contextViewController isKindOfClass:[UINavigationController class]]) {
  309. UINavigationController *navController = ((UINavigationController *)contextViewController);
  310. [navController pushViewController:viewController animated:true];
  311. } else {
  312. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
  313. navController.modalPresentationStyle = UIModalPresentationFullScreen;
  314. navController.navigationBar.barStyle = UIBarStyleBlack;
  315. navController.navigationBar.tintColor = NCBrandColor.sharedInstance.customerText;
  316. navController.navigationBar.barTintColor = NCBrandColor.sharedInstance.customer;
  317. [navController.navigationBar setTranslucent:false];
  318. [contextViewController presentViewController:navController animated:true completion:nil];
  319. }
  320. }
  321. - (void)startTimerErrorNetworking
  322. {
  323. self.timerErrorNetworking = [NSTimer scheduledTimerWithTimeInterval:k_timerErrorNetworking target:self selector:@selector(checkErrorNetworking) userInfo:nil repeats:YES];
  324. }
  325. #pragma --------------------------------------------------------------------------------------------
  326. #pragma mark ===== Account & Communication =====
  327. #pragma --------------------------------------------------------------------------------------------
  328. - (void)settingActiveAccount:(NSString *)activeAccount activeUrl:(NSString *)activeUrl activeUser:(NSString *)activeUser activeUserID:(NSString *)activeUserID activePassword:(NSString *)activePassword
  329. {
  330. self.activeAccount = activeAccount;
  331. self.activeUrl = activeUrl;
  332. self.activeUser = activeUser;
  333. self.activeUserID = activeUserID;
  334. self.activePassword = activePassword;
  335. (void)[NCNetworkingNotificationCenter shared];
  336. [[NCCommunicationCommon shared] setupWithAccount:activeAccount user:activeUser userId:activeUserID password:activePassword url:activeUrl];
  337. [self settingSetupCommunicationCapabilities:activeAccount];
  338. }
  339. - (void)deleteAccount:(NSString *)account wipe:(BOOL)wipe
  340. {
  341. // Push Notification
  342. tableAccount *accountPN = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account]];
  343. [self unsubscribingNextcloudServerPushNotification:accountPN.account url:accountPN.url user:accountPN.user withSubscribing:false];
  344. [self settingActiveAccount:nil activeUrl:nil activeUser:nil activeUserID:nil activePassword:nil];
  345. /* DELETE ALL FILES LOCAL FS */
  346. NSArray *results = [[NCManageDatabase sharedInstance] getTableLocalFilesWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account] sorted:@"ocId" ascending:NO];
  347. for (tableLocalFile *result in results) {
  348. [CCUtility removeFileAtPath:[CCUtility getDirectoryProviderStorageOcId:result.ocId]];
  349. }
  350. // Clear database
  351. [[NCManageDatabase sharedInstance] clearDatabaseWithAccount:account removeAccount:true];
  352. [CCUtility clearAllKeysEndToEnd:account];
  353. [CCUtility clearAllKeysPushNotification:account];
  354. [CCUtility setCertificateError:account error:false];
  355. [CCUtility setPassword:account password:nil];
  356. if (wipe) {
  357. NSArray *listAccount = [[NCManageDatabase sharedInstance] getAccounts];
  358. if ([listAccount count] > 0) {
  359. NSString *newAccount = listAccount[0];
  360. tableAccount *tableAccount = [[NCManageDatabase sharedInstance] setAccountActive:newAccount];
  361. [self settingActiveAccount:newAccount activeUrl:tableAccount.url activeUser:tableAccount.user activeUserID:tableAccount.userID activePassword:[CCUtility getPassword:tableAccount.account]];
  362. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  363. } else {
  364. [self openLoginView:self.window.rootViewController selector:k_intro_login openLoginWeb:false];
  365. }
  366. }
  367. }
  368. - (void)settingSetupCommunicationCapabilities:(NSString *)account
  369. {
  370. NSInteger serverVersionMajor = [[NCManageDatabase sharedInstance] getCapabilitiesServerIntWithAccount:account elements:NCElementsJSON.shared.capabilitiesVersionMajor];
  371. if (serverVersionMajor > 0) {
  372. [[OCNetworking sharedManager].sharedOCCommunication setupNextcloudVersion: serverVersionMajor];
  373. [[NCCommunicationCommon shared] setupWithNextcloudVersion:serverVersionMajor];
  374. }
  375. NSString *webDavRoot = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:account elements:NCElementsJSON.shared.capabilitiesWebDavRoot];
  376. if (webDavRoot != nil) {
  377. [[NCCommunicationCommon shared] setupWithWebDavRoot:webDavRoot];
  378. }
  379. }
  380. #pragma --------------------------------------------------------------------------------------------
  381. #pragma mark ===== Push Notifications =====
  382. #pragma --------------------------------------------------------------------------------------------
  383. - (void)pushNotification
  384. {
  385. // test
  386. if (self.activeAccount.length == 0 || self.maintenanceMode || self.pushKitToken.length == 0)
  387. return;
  388. for (tableAccount *result in [[NCManageDatabase sharedInstance] getAllAccount]) {
  389. NSString *token = [CCUtility getPushNotificationToken:result.account];
  390. if (![token isEqualToString:self.pushKitToken]) {
  391. if (token != nil) {
  392. // unsubscribing + subscribing
  393. [self unsubscribingNextcloudServerPushNotification:result.account url:result.url user:result.user withSubscribing:true];
  394. } else {
  395. [self subscribingNextcloudServerPushNotification:result.account url:result.url user:result.user];
  396. }
  397. }
  398. }
  399. }
  400. - (void)subscribingNextcloudServerPushNotification:(NSString *)account url:(NSString *)url user:(NSString *)user
  401. {
  402. // test
  403. if (self.activeAccount.length == 0 || self.maintenanceMode || self.pushKitToken.length == 0)
  404. return;
  405. [[NCPushNotificationEncryption sharedInstance] generatePushNotificationsKeyPair:account];
  406. NSString *pushTokenHash = [[NCEndToEndEncryption sharedManager] createSHA512:self.pushKitToken];
  407. NSData *pushPublicKey = [CCUtility getPushNotificationPublicKey:account];
  408. NSString *pushDevicePublicKey = [[NSString alloc] initWithData:pushPublicKey encoding:NSUTF8StringEncoding];
  409. NSString *proxyServerPath = [NCBrandOptions sharedInstance].pushNotificationServerProxy;
  410. [[NCCommunication shared] subscribingPushNotificationWithServerUrl:url account:account user:user password:[CCUtility getPassword:account] pushTokenHash:pushTokenHash devicePublicKey:pushDevicePublicKey proxyServerUrl:proxyServerPath customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSString *deviceIdentifier, NSString *signature, NSString *publicKey, NSInteger errorCode, NSString *errorDescription) {
  411. if (errorCode == 0) {
  412. NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [CCUtility getUserAgent]];
  413. [[NCCommunication shared] subscribingPushProxyWithProxyServerUrl:proxyServerPath pushToken:self.pushKitToken deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
  414. if (errorCode == 0) {
  415. NSLog(@"[LOG] Subscribed to Push Notification server & proxy successfully.");
  416. [CCUtility setPushNotificationToken:account token:self.pushKitToken];
  417. [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:deviceIdentifier];
  418. [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:signature];
  419. [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:publicKey];
  420. }
  421. }];
  422. }
  423. }];
  424. }
  425. - (void)unsubscribingNextcloudServerPushNotification:(NSString *)account url:(NSString *)url user:(NSString *)user withSubscribing:(BOOL)subscribing
  426. {
  427. // test
  428. if (self.activeAccount.length == 0 || self.maintenanceMode)
  429. return;
  430. NSString *deviceIdentifier = [CCUtility getPushNotificationDeviceIdentifier:account];
  431. NSString *signature = [CCUtility getPushNotificationDeviceIdentifierSignature:account];
  432. NSString *publicKey = [CCUtility getPushNotificationSubscribingPublicKey:account];
  433. [[NCCommunication shared] unsubscribingPushNotificationWithServerUrl:url account:account user:user password:[CCUtility getPassword:account] customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSInteger errorCode, NSString *errorDescription) {
  434. if (errorCode == 0) {
  435. NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [CCUtility getUserAgent]];
  436. NSString *proxyServerPath = [NCBrandOptions sharedInstance].pushNotificationServerProxy;
  437. [[NCCommunication shared] unsubscribingPushProxyWithProxyServerUrl:proxyServerPath deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
  438. if (errorCode == 0) {
  439. NSLog(@"[LOG] Unsubscribed to Push Notification server & proxy successfully.");
  440. [CCUtility setPushNotificationPublicKey:account data:nil];
  441. [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:nil];
  442. [CCUtility setPushNotificationPrivateKey:account data:nil];
  443. [CCUtility setPushNotificationToken:account token:nil];
  444. [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:nil];
  445. [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:nil];
  446. if (self.pushKitToken != nil && subscribing) {
  447. [self subscribingNextcloudServerPushNotification:account url:url user:user];
  448. }
  449. }
  450. }];
  451. }
  452. }];
  453. }
  454. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
  455. {
  456. //Called when a notification is delivered to a foreground app.
  457. completionHandler(UNNotificationPresentationOptionAlert);
  458. }
  459. -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler
  460. {
  461. completionHandler();
  462. }
  463. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
  464. {
  465. self.pushKitToken = [self stringWithDeviceToken:deviceToken];
  466. [self pushNotification];
  467. }
  468. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  469. {
  470. NSString *message = [userInfo objectForKey:@"subject"];
  471. if (message) {
  472. NSArray *results = [[NCManageDatabase sharedInstance] getAllAccount];
  473. for (tableAccount *result in results) {
  474. if ([CCUtility getPushNotificationPrivateKey:result.account]) {
  475. NSData *decryptionKey = [CCUtility getPushNotificationPrivateKey:result.account];
  476. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:decryptionKey];
  477. if (decryptedMessage) {
  478. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  479. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  480. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  481. BOOL delete = [[json objectForKey:@"delete"] boolValue];
  482. BOOL deleteAll = [[json objectForKey:@"delete-all"] boolValue];
  483. if (delete) {
  484. [self removeNotificationWithNotificationId:nid usingDecryptionKey:decryptionKey];
  485. } else if (deleteAll) {
  486. [self cleanAllNotifications];
  487. }
  488. }
  489. }
  490. }
  491. }
  492. completionHandler(UIBackgroundFetchResultNoData);
  493. }
  494. - (void)cleanAllNotifications
  495. {
  496. [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
  497. }
  498. - (void)removeNotificationWithNotificationId:(NSInteger)notificationId usingDecryptionKey:(NSData *)key
  499. {
  500. // Check in pending notifications
  501. [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
  502. for (UNNotificationRequest *notificationRequest in requests) {
  503. NSString *message = [notificationRequest.content.userInfo objectForKey:@"subject"];
  504. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:key];
  505. if (decryptedMessage) {
  506. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  507. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  508. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  509. if (nid == notificationId) {
  510. [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[notificationRequest.identifier]];
  511. }
  512. }
  513. }
  514. }];
  515. // Check in delivered notifications
  516. [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
  517. for (UNNotification *notification in notifications) {
  518. NSString *message = [notification.request.content.userInfo objectForKey:@"subject"];
  519. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:key];
  520. if (decryptedMessage) {
  521. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  522. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  523. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  524. if (nid == notificationId) {
  525. [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[notification.request.identifier]];
  526. }
  527. }
  528. }
  529. }];
  530. }
  531. - (NSString *)stringWithDeviceToken:(NSData *)deviceToken
  532. {
  533. const char *data = [deviceToken bytes];
  534. NSMutableString *token = [NSMutableString string];
  535. for (NSUInteger i = 0; i < [deviceToken length]; i++) {
  536. [token appendFormat:@"%02.2hhX", data[i]];
  537. }
  538. return [token copy];
  539. }
  540. #pragma --------------------------------------------------------------------------------------------
  541. #pragma mark ==== NotificationCenter ====
  542. #pragma --------------------------------------------------------------------------------------------
  543. - (void)deleteFile:(NSNotification *)notification
  544. {
  545. if (self.arrayDeleteMetadata.count > 0) {
  546. tableMetadata *metadata = self.arrayDeleteMetadata.firstObject;
  547. [self.arrayDeleteMetadata removeObjectAtIndex:0];
  548. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", metadata.account]];
  549. if (account) {
  550. [[NCNetworking shared] deleteMetadata:metadata account:metadata.account url:account.url completion:^(NSInteger errorCode, NSString *errorDescription) { }];
  551. } else {
  552. [self deleteFile:[NSNotification new]];
  553. }
  554. }
  555. }
  556. - (void)moveFile:(NSNotification *)notification
  557. {
  558. if (self.arrayMoveMetadata.count > 0) {
  559. tableMetadata *metadata = self.arrayMoveMetadata.firstObject;
  560. NSString *serverUrlTo = self.arrayMoveServerUrlTo.firstObject;
  561. [self.arrayMoveMetadata removeObjectAtIndex:0];
  562. [self.arrayMoveServerUrlTo removeObjectAtIndex:0];
  563. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", metadata.account]];
  564. if (account) {
  565. [[NCNetworking shared] moveMetadata:metadata serverUrlTo:serverUrlTo overwrite:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
  566. } else {
  567. [self moveFile:[NSNotification new]];
  568. }
  569. }
  570. }
  571. - (void)copyFile:(NSNotification *)notification
  572. {
  573. if (self.arrayCopyMetadata.count > 0) {
  574. tableMetadata *metadata = self.arrayCopyMetadata.firstObject;
  575. NSString *serverUrlTo = self.arrayCopyServerUrlTo.firstObject;
  576. [self.arrayCopyMetadata removeObjectAtIndex:0];
  577. [self.arrayCopyServerUrlTo removeObjectAtIndex:0];
  578. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", metadata.account]];
  579. if (account) {
  580. [[NCNetworking shared] copyMetadata:metadata serverUrlTo:serverUrlTo overwrite:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
  581. } else {
  582. [self copyFile:[NSNotification new]];
  583. }
  584. }
  585. }
  586. - (void)uploadedFile:(NSNotification *)notification
  587. {
  588. NSDictionary *userInfo = notification.userInfo;
  589. tableMetadata *metadata = userInfo[@"metadata"];
  590. NSInteger errorCode = [userInfo[@"errorCode"] integerValue];
  591. if (errorCode == 0) {
  592. // verify delete Asset Local Identifiers in auto upload
  593. [[NCUtility sharedInstance] deleteAssetLocalIdentifiersWithAccount:metadata.account sessionSelector:selectorUploadAutoUpload];
  594. }
  595. }
  596. #pragma --------------------------------------------------------------------------------------------
  597. #pragma mark ===== Quick Actions - ShotcutItem =====
  598. #pragma --------------------------------------------------------------------------------------------
  599. - (void)configDynamicShortcutItems
  600. {
  601. NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
  602. UIApplicationShortcutIcon *shortcutMediaIcon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"media"];
  603. UIApplicationShortcutItem *shortcutMedia = [[UIApplicationShortcutItem alloc] initWithType:[NSString stringWithFormat:@"%@.media", bundleId] localizedTitle:NSLocalizedString(@"_media_", nil) localizedSubtitle:nil icon:shortcutMediaIcon userInfo:nil];
  604. // add the array to our app
  605. if (shortcutMedia)
  606. [UIApplication sharedApplication].shortcutItems = @[shortcutMedia];
  607. }
  608. - (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
  609. {
  610. BOOL handledShortCutItem = [self handleShortCutItem:shortcutItem];
  611. completionHandler(handledShortCutItem);
  612. }
  613. - (BOOL)handleShortCutItem:(UIApplicationShortcutItem *)shortcutItem
  614. {
  615. BOOL handled = NO;
  616. NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
  617. NSString *shortcutMedia = [NSString stringWithFormat:@"%@.media", bundleId];
  618. if ([shortcutItem.type isEqualToString:shortcutMedia] && self.activeAccount) {
  619. dispatch_async(dispatch_get_main_queue(), ^{
  620. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  621. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  622. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  623. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  624. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  625. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  626. if (splitViewController.isCollapsed) {
  627. [navigationControllerMaster popToRootViewControllerAnimated:false];
  628. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  629. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  630. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  631. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  632. [tabBarController setSelectedIndex: k_tabBarApplicationIndexMedia];
  633. }
  634. }
  635. } else {
  636. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  637. [tabBarController setSelectedIndex: k_tabBarApplicationIndexMedia];
  638. }
  639. }
  640. }
  641. }
  642. }
  643. });
  644. handled = YES;
  645. }
  646. return handled;
  647. }
  648. #pragma --------------------------------------------------------------------------------------------
  649. #pragma mark ===== ApplicationIconBadgeNumber =====
  650. #pragma --------------------------------------------------------------------------------------------
  651. - (void)updateApplicationIconBadgeNumber
  652. {
  653. if (self.activeAccount.length == 0 || self.maintenanceMode)
  654. return;
  655. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  656. NSInteger counterDownload = [[NCOperationQueue shared] downloadCount];
  657. NSInteger counterUpload = [[[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"status == %d OR status == %d OR status == %d", k_metadataStatusWaitUpload, k_metadataStatusInUpload, k_metadataStatusUploading] sorted:@"fileName" ascending:true] count];
  658. NSInteger total = counterDownload + counterUpload;
  659. dispatch_async(dispatch_get_main_queue(), ^{
  660. [UIApplication sharedApplication].applicationIconBadgeNumber = total;
  661. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  662. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  663. UINavigationController *navigationController = (UINavigationController *)[splitViewController.viewControllers firstObject];
  664. if ([navigationController isKindOfClass:[UINavigationController class]]) {
  665. UITabBarController *tabBarController = (UITabBarController *)navigationController.topViewController;
  666. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  667. UITabBarItem *tabBarItem = [tabBarController.tabBar.items objectAtIndex:0];
  668. if (total > 0) {
  669. [tabBarItem setBadgeValue:[NSString stringWithFormat:@"%li", (unsigned long)total]];
  670. } else {
  671. [tabBarItem setBadgeValue:nil];
  672. }
  673. }
  674. }
  675. }
  676. });
  677. });
  678. }
  679. #pragma --------------------------------------------------------------------------------------------
  680. #pragma mark ===== TabBarController =====
  681. #pragma --------------------------------------------------------------------------------------------
  682. - (void)createTabBarController:(UITabBarController *)tabBarController
  683. {
  684. UITabBarItem *item;
  685. NSLayoutConstraint *constraint;
  686. CGFloat safeAreaBottom = safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  687. // File
  688. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexFile];
  689. [item setTitle:NSLocalizedString(@"_home_", nil)];
  690. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarFiles"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  691. item.selectedImage = item.image;
  692. // Favorites
  693. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexFavorite];
  694. [item setTitle:NSLocalizedString(@"_favorites_", nil)];
  695. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"favorite"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  696. item.selectedImage = item.image;
  697. // (PLUS INVISIBLE)
  698. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexPlusHide];
  699. item.title = @"";
  700. item.image = nil;
  701. item.enabled = false;
  702. // Media
  703. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexMedia];
  704. [item setTitle:NSLocalizedString(@"_media_", nil)];
  705. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"media"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  706. item.selectedImage = item.image;
  707. // More
  708. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexMore];
  709. [item setTitle:NSLocalizedString(@"_more_", nil)];
  710. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarMore"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  711. item.selectedImage = item.image;
  712. // Plus Button
  713. int buttonSize = 57;
  714. UIImage *buttonImage = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarPlus"] width:120 height:120 color:UIColor.whiteColor];
  715. UIButton *buttonPlus = [UIButton buttonWithType:UIButtonTypeCustom];
  716. buttonPlus.tag = 99;
  717. [buttonPlus setImage:buttonImage forState:UIControlStateNormal];
  718. buttonPlus.backgroundColor = NCBrandColor.sharedInstance.brand;
  719. buttonPlus.layer.cornerRadius = buttonSize / 2;
  720. buttonPlus.layer.masksToBounds = NO;
  721. buttonPlus.layer.shadowOffset = CGSizeMake(0, 0);
  722. buttonPlus.layer.shadowRadius = 3.0f;
  723. buttonPlus.layer.shadowOpacity = 0.5;
  724. [buttonPlus addTarget:self action:@selector(handleTouchTabbarCenter:) forControlEvents:UIControlEventTouchUpInside];
  725. [buttonPlus setTranslatesAutoresizingMaskIntoConstraints:NO];
  726. [tabBarController.tabBar addSubview:buttonPlus];
  727. if (safeAreaBottom > 0) {
  728. // X
  729. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
  730. [tabBarController.view addConstraint:constraint];
  731. // Y
  732. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeTop multiplier:1.0 constant:-(buttonSize / 2)];
  733. [tabBarController.view addConstraint:constraint];
  734. // Width
  735. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  736. [tabBarController.view addConstraint:constraint];
  737. // Height
  738. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  739. [tabBarController.view addConstraint:constraint];
  740. } else {
  741. // X
  742. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
  743. [tabBarController.view addConstraint:constraint];
  744. // Y
  745. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:-(buttonSize / 2)];
  746. [tabBarController.view addConstraint:constraint];
  747. // Width
  748. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  749. [tabBarController.view addConstraint:constraint];
  750. // Height
  751. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  752. [tabBarController.view addConstraint:constraint];
  753. }
  754. }
  755. - (void)handleTouchTabbarCenter:(id)sender
  756. {
  757. // Test Maintenance
  758. if (self.maintenanceMode)
  759. return;
  760. tableDirectory *tableDirectory = [[NCManageDatabase sharedInstance] getTableDirectoryWithPredicate:[NSPredicate predicateWithFormat:@"account == %@ AND serverUrl == %@", self.activeAccount, self.activeMain.serverUrl]];
  761. if ([tableDirectory.permissions containsString:@"CK"]) {
  762. UIViewController *vc = _activeMain.splitViewController.viewControllers[0];
  763. [self showMenuInViewController: vc];
  764. } else {
  765. [[NCContentPresenter shared] messageNotification:@"_warning_" description:@"_no_permission_add_file_" delay:k_dismissAfterSecond type:messageTypeInfo errorCode:0];
  766. }
  767. }
  768. - (NSString *)getTabBarControllerActiveServerUrl
  769. {
  770. NSString *serverUrl = [CCUtility getHomeServerUrlActiveUrl:self.activeUrl];
  771. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  772. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  773. UINavigationController *masterNavigationController = [splitViewController.viewControllers firstObject];
  774. if ([masterNavigationController isKindOfClass:[UINavigationController class]]) {
  775. UITabBarController *tabBarController = [masterNavigationController.viewControllers firstObject];
  776. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  777. NSInteger index = tabBarController.selectedIndex;
  778. // select active serverUrl
  779. if (index == k_tabBarApplicationIndexFile) {
  780. serverUrl = self.activeMain.serverUrl;
  781. } else if (index == k_tabBarApplicationIndexFavorite) {
  782. if (self.activeFavorites.serverUrl)
  783. serverUrl = self.activeFavorites.serverUrl;
  784. } else if (index == k_tabBarApplicationIndexMedia) {
  785. serverUrl = [[NCManageDatabase sharedInstance] getAccountAutoUploadPath:self.activeUrl];
  786. }
  787. }
  788. }
  789. }
  790. return serverUrl;
  791. }
  792. #pragma --------------------------------------------------------------------------------------------
  793. #pragma mark ===== Theming Color =====
  794. #pragma --------------------------------------------------------------------------------------------
  795. - (void)settingThemingColorBrand
  796. {
  797. if (self.activeAccount.length == 0 || self.maintenanceMode)
  798. return;
  799. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  800. if ([NCBrandOptions sharedInstance].use_themingColor) {
  801. NSString *themingColor = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.activeAccount elements:NCElementsJSON.shared.capabilitiesThemingColor];
  802. NSString *themingColorElement = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.activeAccount elements:NCElementsJSON.shared.capabilitiesThemingColorElement];
  803. NSString *themingColorText = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.activeAccount elements:NCElementsJSON.shared.capabilitiesThemingColorText];
  804. [CCGraphics settingThemingColor:themingColor themingColorElement:themingColorElement themingColorText:themingColorText];
  805. UIColor *color = NCBrandColor.sharedInstance.brand;
  806. BOOL isTooLight = NCBrandColor.sharedInstance.brand.isTooLight;
  807. BOOL isTooDark = NCBrandColor.sharedInstance.brand.isTooDark;
  808. if (isTooLight) {
  809. color = [NCBrandColor.sharedInstance.brand darkerBy:10];
  810. } else if (isTooDark) {
  811. color = [NCBrandColor.sharedInstance.brand lighterBy:10];
  812. }
  813. NCBrandColor.sharedInstance.brand = color;
  814. } else {
  815. NCBrandColor.sharedInstance.brand = NCBrandColor.sharedInstance.customer;
  816. NCBrandColor.sharedInstance.brandElement = NCBrandColor.sharedInstance.customer;
  817. NCBrandColor.sharedInstance.brandText = NCBrandColor.sharedInstance.customerText;
  818. }
  819. [[NCMainCommon sharedInstance] createImagesThemingColor];
  820. [NCBrandColor.sharedInstance setDarkMode];
  821. });
  822. [self.window setTintColor:NCBrandColor.sharedInstance.textView];
  823. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_changeTheming object:nil];
  824. }
  825. - (void)changeTheming:(UIViewController *)viewController tableView:(UITableView *)tableView collectionView:(UICollectionView *)collectionView form:(BOOL)form
  826. {
  827. // View
  828. if (form) viewController.view.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  829. else viewController.view.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  830. // NavigationBar
  831. if (viewController.navigationController.navigationBar) {
  832. if (!NCCommunication.shared.isNetworkReachable) {
  833. [viewController.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : NCBrandColor.sharedInstance.connectionNo}];
  834. }
  835. }
  836. [self configureNavBarForViewController:viewController];
  837. //tabBar
  838. if (viewController.tabBarController.tabBar) {
  839. viewController.tabBarController.tabBar.translucent = NO;
  840. viewController.tabBarController.tabBar.barTintColor = NCBrandColor.sharedInstance.backgroundView;
  841. viewController.tabBarController.tabBar.tintColor = NCBrandColor.sharedInstance.brandElement;
  842. }
  843. // TableView
  844. if (tableView) {
  845. if (form) tableView.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  846. else tableView.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  847. tableView.separatorColor = NCBrandColor.sharedInstance.separator;
  848. [tableView reloadData];
  849. }
  850. // CollectionView
  851. if (collectionView) {
  852. if (form) collectionView.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  853. else collectionView.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  854. [collectionView reloadData];
  855. }
  856. }
  857. #pragma --------------------------------------------------------------------------------------------
  858. #pragma mark ===== Fetch =====
  859. #pragma --------------------------------------------------------------------------------------------
  860. - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  861. {
  862. // Test Maintenance
  863. if (self.activeAccount.length == 0 || self.maintenanceMode) {
  864. completionHandler(UIBackgroundFetchResultNoData);
  865. return;
  866. }
  867. NSLog(@"[LOG] Start perform Fetch With Completion Handler");
  868. // Verify new photo
  869. [[NCAutoUpload sharedInstance] initStateAutoUpload];
  870. // after 20 sec
  871. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  872. NSArray *records = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"session != ''"] sorted:nil ascending:NO];
  873. if ([records count] > 0) {
  874. completionHandler(UIBackgroundFetchResultNewData);
  875. } else {
  876. completionHandler(UIBackgroundFetchResultNoData);
  877. }
  878. NSLog(@"[LOG] End 20 sec. perform Fetch With Completion Handler");
  879. });
  880. }
  881. #pragma --------------------------------------------------------------------------------------------
  882. #pragma mark ===== Operation Networking & Session =====
  883. #pragma --------------------------------------------------------------------------------------------
  884. //
  885. // Method called by the system when all the background task has end
  886. //
  887. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
  888. {
  889. NSLog(@"[LOG] Start handle Events For Background URLSession: %@", identifier);
  890. dispatch_async(dispatch_get_main_queue(), ^{
  891. self.backgroundSessionCompletionHandler = completionHandler;
  892. void (^completionHandler)() = self.backgroundSessionCompletionHandler;
  893. self.backgroundSessionCompletionHandler = nil;
  894. completionHandler();
  895. });
  896. }
  897. #pragma --------------------------------------------------------------------------------------------
  898. #pragma mark ===== Process Load Upload < k_timerProcess seconds > =====
  899. #pragma --------------------------------------------------------------------------------------------
  900. - (void)loadAutoUpload
  901. {
  902. if (self.activeAccount.length == 0 || self.maintenanceMode)
  903. return;
  904. tableMetadata *metadataForUpload;
  905. long counterUpload = 0;
  906. NSUInteger sizeUpload = 0;
  907. NSMutableArray *uploaded = [NSMutableArray new];
  908. NSPredicate *predicate;
  909. long maxConcurrentOperationUpload = k_maxConcurrentOperation;
  910. NSArray *metadatasUpload = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"status == %d OR status == %d", k_metadataStatusInUpload, k_metadataStatusUploading] sorted:nil ascending:true];
  911. // E2EE only 1
  912. for(tableMetadata *metadata in metadatasUpload) {
  913. if ([CCUtility isFolderEncrypted:metadata.serverUrl e2eEncrypted:metadata.e2eEncrypted account:metadata.account]) return;
  914. }
  915. // Counter
  916. counterUpload = [metadatasUpload count];
  917. // Size
  918. for (tableMetadata *metadata in metadatasUpload) {
  919. sizeUpload = sizeUpload + metadata.size;
  920. }
  921. NSLog(@"%@", [NSString stringWithFormat:@"[LOG] PROCESS-AUTO-UPLOAD Upload %ld - %@", counterUpload, [CCUtility transformedSize:sizeUpload]]);
  922. // Stop Timer
  923. [_timerProcessAutoUpload invalidate];
  924. // ------------------------- <selector Upload> -------------------------
  925. while (counterUpload < maxConcurrentOperationUpload) {
  926. if (sizeUpload > k_maxSizeOperationUpload) {
  927. break;
  928. }
  929. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
  930. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadFile, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
  931. } else {
  932. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadFile, k_metadataStatusWaitUpload];
  933. }
  934. metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"date" ascending:YES];
  935. // Verify modify file
  936. if ([uploaded containsObject:[NSString stringWithFormat:@"%@%@%@", metadataForUpload.account, metadataForUpload.serverUrl, metadataForUpload.fileName]]) {
  937. break;
  938. }
  939. if (metadataForUpload) {
  940. // Verify modify file
  941. BOOL isAleadyInUpload = false;
  942. for (tableMetadata *metadata in metadatasUpload) {
  943. if ([metadataForUpload.account isEqualToString:metadata.account] && [metadataForUpload.serverUrl isEqualToString:metadata.serverUrl] && [metadataForUpload.fileName isEqualToString:metadata.fileName]) {
  944. isAleadyInUpload = true;
  945. }
  946. }
  947. if (isAleadyInUpload == false) {
  948. if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
  949. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
  950. maxConcurrentOperationUpload = 1;
  951. metadataForUpload.status = k_metadataStatusInUpload;
  952. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  953. [[NCNetworking shared] uploadWithMetadata:metadata];
  954. break;
  955. } else {
  956. metadataForUpload.status = k_metadataStatusInUpload;
  957. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  958. [[NCNetworking shared] uploadWithMetadata:metadata];
  959. counterUpload++;
  960. sizeUpload = sizeUpload + metadata.size;
  961. // For verify modify file
  962. [uploaded addObject:[NSString stringWithFormat:@"%@%@%@", metadata.account, metadata.serverUrl, metadata.fileName]];
  963. }
  964. } else {
  965. break;
  966. }
  967. } else {
  968. break;
  969. }
  970. }
  971. // ------------------------- <selector Auto Upload> -------------------------
  972. while (counterUpload < maxConcurrentOperationUpload) {
  973. if (sizeUpload > k_maxSizeOperationUpload) {
  974. break;
  975. }
  976. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
  977. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUpload, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
  978. } else {
  979. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadAutoUpload, k_metadataStatusWaitUpload];
  980. }
  981. metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"date" ascending:YES];
  982. if (metadataForUpload) {
  983. if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
  984. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
  985. maxConcurrentOperationUpload = 1;
  986. metadataForUpload.status = k_metadataStatusInUpload;
  987. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  988. [[NCNetworking shared] uploadWithMetadata:metadata];
  989. break;
  990. } else {
  991. metadataForUpload.status = k_metadataStatusInUpload;
  992. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  993. [[NCNetworking shared] uploadWithMetadata:metadata];
  994. counterUpload++;
  995. sizeUpload = sizeUpload + metadata.size;
  996. }
  997. } else {
  998. break;
  999. }
  1000. }
  1001. // ------------------------- <selector Auto Upload All> ----------------------
  1002. // Verify num error k_maxErrorAutoUploadAll after STOP (100)
  1003. NSArray *metadatas = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %i", selectorUploadAutoUploadAll, k_metadataStatusUploadError] sorted:@"date" ascending:YES];
  1004. NSInteger errorCount = [metadatas count];
  1005. if (errorCount >= k_maxErrorAutoUploadAll) {
  1006. [[NCContentPresenter shared] messageNotification:@"_error_" description:@"_too_errors_automatic_all_" delay:k_dismissAfterSecond type:messageTypeError errorCode:k_CCErrorInternalError];
  1007. } else {
  1008. while (counterUpload < maxConcurrentOperationUpload) {
  1009. if (sizeUpload > k_maxSizeOperationUpload) {
  1010. break;
  1011. }
  1012. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
  1013. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
  1014. } else {
  1015. predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload];
  1016. }
  1017. metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"session" ascending:YES];
  1018. if (metadataForUpload) {
  1019. if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
  1020. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
  1021. maxConcurrentOperationUpload = 1;
  1022. metadataForUpload.status = k_metadataStatusInUpload;
  1023. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  1024. [[NCNetworking shared] uploadWithMetadata:metadata];
  1025. break;
  1026. } else {
  1027. metadataForUpload.status = k_metadataStatusInUpload;
  1028. tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
  1029. [[NCNetworking shared] uploadWithMetadata:metadata];
  1030. counterUpload++;
  1031. sizeUpload = sizeUpload + metadata.size;
  1032. }
  1033. } else {
  1034. break;
  1035. }
  1036. }
  1037. }
  1038. // Start Timer
  1039. _timerProcessAutoUpload = [NSTimer scheduledTimerWithTimeInterval:k_timerProcessAutoUpload target:self selector:@selector(loadAutoUpload) userInfo:nil repeats:YES];
  1040. }
  1041. - (void)startLoadAutoUpload
  1042. {
  1043. if (self.timerProcessAutoUpload.isValid) {
  1044. [self performSelectorOnMainThread:@selector(loadAutoUpload) withObject:nil waitUntilDone:YES];
  1045. }
  1046. }
  1047. - (void)verifyUploadBackgroundLost
  1048. {
  1049. NSString *sessionExtension = [[NCCommunicationCommon shared] sessionIdentifierExtension];
  1050. NSArray *metadatasUploading = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"session != %@ AND status == %d", sessionExtension, k_metadataStatusUploading] sorted:nil ascending:true];
  1051. for (tableMetadata *metadata in metadatasUploading) {
  1052. NSURLSession *session;
  1053. if ([metadata.session isEqualToString:NCCommunicationCommon.shared.sessionIdentifierBackground]) {
  1054. session = NCCommunicationBackground.shared.sessionManagerTransfer;
  1055. } else if ([metadata.session isEqualToString:NCCommunicationCommon.shared.sessionIdentifierBackgroundWWan]) {
  1056. session = NCCommunicationBackground.shared.sessionManagerTransferWWan;
  1057. } else if ([metadata.session isEqualToString:NCCommunicationCommon.shared.sessionIdentifierExtension]) {
  1058. session = NCCommunicationBackground.shared.sessionManagerTransferExtension;
  1059. }
  1060. [session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
  1061. NSURLSessionTask *findTask;
  1062. for (NSURLSessionTask *task in uploadTasks) {
  1063. if (task.taskIdentifier == metadata.sessionTaskIdentifier) {
  1064. findTask = task;
  1065. }
  1066. }
  1067. if (!findTask) {
  1068. metadata.sessionTaskIdentifier = k_taskIdentifierDone;
  1069. metadata.status = k_metadataStatusWaitUpload;
  1070. (void)[[NCManageDatabase sharedInstance] addMetadata:metadata];
  1071. }
  1072. }];
  1073. }
  1074. }
  1075. #pragma --------------------------------------------------------------------------------------------
  1076. #pragma mark ===== OpenURL =====
  1077. #pragma --------------------------------------------------------------------------------------------
  1078. // Method called from iOS system to send a file from other app.
  1079. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
  1080. {
  1081. if (self.activeAccount.length == 0 || self.maintenanceMode)
  1082. return YES;
  1083. NSString *scheme = url.scheme;
  1084. dispatch_time_t timer = 0;
  1085. if (self.activeMain == nil) timer = 1;
  1086. if ([scheme isEqualToString:@"nextcloud"]) {
  1087. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timer * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1088. NSString *action = url.host;
  1089. if ([action isEqualToString:@"open-file"]) {
  1090. NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
  1091. NSArray *queryItems = urlComponents.queryItems;
  1092. NSString *user = [CCUtility valueForKey:@"user" fromQueryItems:queryItems];
  1093. NSString *path = [CCUtility valueForKey:@"path" fromQueryItems:queryItems];
  1094. NSString *link = [CCUtility valueForKey:@"link" fromQueryItems:queryItems];
  1095. tableAccount *matchedAccount = nil;
  1096. // verify parameter
  1097. if (user.length == 0 || path.length == 0 || [[NSURL URLWithString:link] host].length == 0) {
  1098. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_error_parameter_schema_", nil) preferredStyle:UIAlertControllerStyleAlert];
  1099. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  1100. [alertController addAction:okAction];
  1101. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  1102. } else {
  1103. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountActive];
  1104. if (account) {
  1105. NSURL *activeAccountURL = [NSURL URLWithString:account.url];
  1106. NSString *activeAccountUser = account.user;
  1107. if ([link containsString:activeAccountURL.host] && [user isEqualToString:activeAccountUser]) {
  1108. matchedAccount = account;
  1109. } else {
  1110. NSArray *accounts = [[NCManageDatabase sharedInstance] getAllAccount];
  1111. for (tableAccount *account in accounts) {
  1112. NSURL *accountURL = [NSURL URLWithString:account.url];
  1113. NSString *accountUser = account.user;
  1114. if ([link containsString:accountURL.host] && [user isEqualToString:accountUser]) {
  1115. matchedAccount = [[NCManageDatabase sharedInstance] setAccountActive:account.account];
  1116. [self settingActiveAccount:matchedAccount.account activeUrl:matchedAccount.url activeUser:matchedAccount.user activeUserID:matchedAccount.userID activePassword:[CCUtility getPassword:matchedAccount.account]];
  1117. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  1118. }
  1119. }
  1120. }
  1121. if (matchedAccount) {
  1122. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  1123. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  1124. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  1125. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  1126. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  1127. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  1128. if (splitViewController.isCollapsed) {
  1129. [navigationControllerMaster popToRootViewControllerAnimated:false];
  1130. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  1131. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  1132. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  1133. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  1134. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  1135. [tabBarController setSelectedIndex: k_tabBarApplicationIndexFile];
  1136. }
  1137. }
  1138. }
  1139. } else {
  1140. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  1141. [tabBarController setSelectedIndex: k_tabBarApplicationIndexFile];
  1142. }
  1143. }
  1144. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1145. [self.activeMain.navigationController popToRootViewControllerAnimated:NO];
  1146. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1147. NSString *fileNamePath = [NSString stringWithFormat:@"%@%@/%@", matchedAccount.url, k_webDAV, path];
  1148. if ([path containsString:@"/"]) {
  1149. // Push
  1150. NSString *fileName = [[path stringByDeletingLastPathComponent] lastPathComponent];
  1151. NSString *serverUrl = [CCUtility deletingLastPathComponentFromServerUrl:[NSString stringWithFormat:@"%@%@/%@", matchedAccount.url, k_webDAV, [path stringByDeletingLastPathComponent]]];
  1152. tableMetadata *metadata = [[NCManageDatabase sharedInstance] createMetadataWithAccount:matchedAccount.account fileName:fileName ocId:[[NSUUID UUID] UUIDString] serverUrl:serverUrl url:@"" contentType:@""];
  1153. [self.activeMain performSegueDirectoryWithMetadata:metadata blinkFileNamePath:fileNamePath];
  1154. } else {
  1155. // Reload folder
  1156. NSString *serverUrl = [NSString stringWithFormat:@"%@%@", matchedAccount.url, k_webDAV];
  1157. self.activeMain.blinkFileNamePath = fileNamePath;
  1158. [self.activeMain readFolder:serverUrl];
  1159. }
  1160. });
  1161. });
  1162. }
  1163. }
  1164. }
  1165. } else {
  1166. NSString *domain = [[NSURL URLWithString:link] host];
  1167. NSString *fileName = [path lastPathComponent];
  1168. NSString *message = [NSString stringWithFormat:NSLocalizedString(@"_account_not_available_", nil), user, domain, fileName];
  1169. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_info_", nil) message:message preferredStyle:UIAlertControllerStyleAlert];
  1170. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  1171. [alertController addAction:okAction];
  1172. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  1173. }
  1174. }
  1175. }
  1176. }
  1177. });
  1178. return YES;
  1179. }
  1180. NSError *error;
  1181. NSLog(@"[LOG] the path is: %@", url.path);
  1182. NSArray *splitedUrl = [url.path componentsSeparatedByString:@"/"];
  1183. self.fileNameUpload = [NSString stringWithFormat:@"%@",[splitedUrl objectAtIndex:([splitedUrl count]-1)]];
  1184. if (self.activeAccount) {
  1185. [[NSFileManager defaultManager]removeItemAtPath:[NSTemporaryDirectory() stringByAppendingString:self.fileNameUpload] error:nil];
  1186. [[NSFileManager defaultManager]moveItemAtPath:url.path toPath:[NSTemporaryDirectory() stringByAppendingString:self.fileNameUpload] error:&error];
  1187. if (error == nil) {
  1188. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  1189. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  1190. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  1191. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  1192. UIViewController *uploadNavigationViewController = [[UIStoryboard storyboardWithName:@"CCUploadFromOtherUpp" bundle:nil] instantiateViewControllerWithIdentifier:@"CCUploadNavigationViewController"];
  1193. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timer * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  1194. [navigationControllerMaster presentViewController:uploadNavigationViewController animated:YES completion:nil];
  1195. });
  1196. }
  1197. }
  1198. }
  1199. }
  1200. return YES;
  1201. }
  1202. #pragma --------------------------------------------------------------------------------------------
  1203. #pragma mark ===== Passcode + Delegate =====
  1204. #pragma --------------------------------------------------------------------------------------------
  1205. - (void)passcodeWithAutomaticallyPromptForBiometricValidation:(BOOL)automaticallyPromptForBiometricValidation
  1206. {
  1207. LAContext *laContext = [LAContext new];
  1208. NSError *error;
  1209. BOOL isBiometryAvailable = false;
  1210. if ([[CCUtility getPasscode] length] == 0 || [self.activeAccount length] == 0 || [CCUtility getNotPasscodeAtStart]) return;
  1211. if (!self.passcodeViewController.view.window) {
  1212. self.passcodeViewController = [[TOPasscodeViewController alloc] initWithStyle:TOPasscodeViewStyleTranslucentLight passcodeType:TOPasscodeTypeSixDigits];
  1213. if (@available(iOS 13.0, *)) {
  1214. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  1215. self.passcodeViewController.style = TOPasscodeViewStyleTranslucentDark;
  1216. }
  1217. }
  1218. self.passcodeViewController.delegate = self;
  1219. self.passcodeViewController.allowCancel = false;
  1220. self.passcodeViewController.keypadButtonShowLettering = false;
  1221. if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
  1222. if (error == NULL) {
  1223. if (laContext.biometryType == LABiometryTypeFaceID) {
  1224. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeFaceID;
  1225. self.passcodeViewController.allowBiometricValidation = true;
  1226. isBiometryAvailable = true;
  1227. } else if (laContext.biometryType == LABiometryTypeTouchID) {
  1228. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeTouchID;
  1229. self.passcodeViewController.allowBiometricValidation = true;
  1230. isBiometryAvailable = true;
  1231. } else {
  1232. isBiometryAvailable = false;
  1233. NSLog(@"No Biometric support");
  1234. }
  1235. }
  1236. }
  1237. [self.window.rootViewController presentViewController:self.passcodeViewController animated:YES completion:nil];
  1238. }
  1239. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1240. if (automaticallyPromptForBiometricValidation && self.passcodeViewController.view.window) {
  1241. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions sharedInstance] brand] reply:^(BOOL success, NSError * _Nullable error) {
  1242. if (success) {
  1243. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1244. [self.passcodeViewController dismissViewControllerAnimated:YES completion:nil];
  1245. });
  1246. }
  1247. }];
  1248. }
  1249. });
  1250. }
  1251. - (void)didTapCancelInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  1252. {
  1253. [passcodeViewController dismissViewControllerAnimated:YES completion:nil];
  1254. }
  1255. - (BOOL)passcodeViewController:(TOPasscodeViewController *)passcodeViewController isCorrectCode:(NSString *)code
  1256. {
  1257. return [code isEqualToString:[CCUtility getPasscode]];
  1258. }
  1259. - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  1260. {
  1261. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions sharedInstance] brand] reply:^(BOOL success, NSError * _Nullable error) {
  1262. if (success) {
  1263. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1264. [passcodeViewController dismissViewControllerAnimated:YES completion:nil];
  1265. });
  1266. }
  1267. }];
  1268. }
  1269. #pragma --------------------------------------------------------------------------------------------
  1270. #pragma mark ===== Maintenance Mode =====
  1271. #pragma --------------------------------------------------------------------------------------------
  1272. - (void)maintenanceMode:(BOOL)mode
  1273. {
  1274. self.maintenanceMode = mode;
  1275. }
  1276. #pragma --------------------------------------------------------------------------------------------
  1277. #pragma mark ===== UPGRADE =====
  1278. #pragma --------------------------------------------------------------------------------------------
  1279. - (BOOL)upgrade
  1280. {
  1281. #ifdef DEBUG
  1282. //self.maintenanceMode = YES;
  1283. #endif
  1284. NSString *actualVersion = [CCUtility getVersion];
  1285. NSString *actualBuild = [CCUtility getBuild];
  1286. /* ---------------------- UPGRADE VERSION ----------------------- */
  1287. // VERSION < 2.17.6
  1288. if (([actualVersion compare:@"2.17.6" options:NSNumericSearch] == NSOrderedAscending)) {
  1289. // Remove All old Photo Library
  1290. [[NCManageDatabase sharedInstance] clearTable:[tablePhotoLibrary class] account:nil];
  1291. }
  1292. // VERSION == 2.17.6
  1293. if ([actualVersion isEqualToString:@"2.17.6"]) {
  1294. // Build < 10
  1295. if (([actualBuild compare:@"10" options:NSNumericSearch] == NSOrderedAscending) || actualBuild == nil) {
  1296. // Remove All old Photo Library
  1297. //[[NCManageDatabase sharedInstance] clearTable:[tablePhotoLibrary class] account:nil];
  1298. }
  1299. }
  1300. if (([actualVersion compare:@"2.19.1" options:NSNumericSearch] == NSOrderedAscending)) {
  1301. [[NCManageDatabase sharedInstance] clearTable:[tableMetadata class] account:nil];
  1302. }
  1303. if (([actualVersion compare:@"2.22.0" options:NSNumericSearch] == NSOrderedAscending)) {
  1304. NSArray *records = [[NCManageDatabase sharedInstance] getTableLocalFilesWithPredicate:[NSPredicate predicateWithFormat:@"#size > 0"] sorted:@"account" ascending:NO];
  1305. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
  1306. NSString *account = @"";
  1307. NSString *directoryUser = @"";
  1308. NSString *fileName;
  1309. for (tableLocalFile *record in records) {
  1310. if (![account isEqualToString:record.account]) {
  1311. tableAccount *tableAccount = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", record.account]];
  1312. if (tableAccount) {
  1313. directoryUser = [CCUtility getDirectoryActiveUser:tableAccount.user activeUrl:tableAccount.url];
  1314. account = record.account;
  1315. }
  1316. }
  1317. fileName = [NSString stringWithFormat:@"%@/%@", directoryUser, record.ocId];
  1318. if (![directoryUser isEqualToString:@""] && [[NSFileManager defaultManager] fileExistsAtPath:fileName]) {
  1319. [CCUtility moveFileAtPath:fileName toPath:[CCUtility getDirectoryProviderStorageOcId:record.ocId fileNameView:record.fileName]];
  1320. }
  1321. }
  1322. });
  1323. }
  1324. if ([actualVersion isEqualToString:@"2.22.9"]) {
  1325. if (([actualBuild compare:@"8" options:NSNumericSearch] == NSOrderedAscending) || actualBuild == nil) {
  1326. [[NCManageDatabase sharedInstance] clearTable:[tableActivity class] account:nil];
  1327. [[NCManageDatabase sharedInstance] clearTable:[tableActivitySubjectRich class] account:nil];
  1328. [[NCManageDatabase sharedInstance] clearTable:[tableActivityPreview class] account:nil];
  1329. }
  1330. }
  1331. if (([actualVersion compare:@"2.23.4" options:NSNumericSearch] == NSOrderedAscending)) {
  1332. NSArray *records = [[NCManageDatabase sharedInstance] getAllAccount];
  1333. for (tableAccount *record in records) {
  1334. [CCUtility setPassword:record.account password:record.password];
  1335. [[NCManageDatabase sharedInstance] removePasswordAccount:record.account];
  1336. }
  1337. }
  1338. return YES;
  1339. }
  1340. @end