blob: 569ffaf0eedd90617e384273e2044347f6a3db3b [file] [log] [blame]
Alexandre Lision745e4d62015-03-22 20:03:10 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision745e4d62015-03-22 20:03:10 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lision745e4d62015-03-22 20:03:10 -040018 */
19#import "RingWizardWC.h"
20
Alexandre Lision54187a22016-04-04 09:45:52 -040021//Cocoa
22#import <AddressBook/AddressBook.h>
23#import <Quartz/Quartz.h>
24
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040025//Qt
26#import <QUrl>
Alexandre Lision54187a22016-04-04 09:45:52 -040027#import <QPixmap>
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040028
29//LRC
Alexandre Lision745e4d62015-03-22 20:03:10 -040030#import <accountmodel.h>
31#import <protocolmodel.h>
Alexandre Lision54187a22016-04-04 09:45:52 -040032#import <profilemodel.h>
Alexandre Lision745e4d62015-03-22 20:03:10 -040033#import <QItemSelectionModel>
34#import <account.h>
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040035#import <certificate.h>
Alexandre Lision54187a22016-04-04 09:45:52 -040036#import <profilemodel.h>
37#import <profile.h>
38#import <person.h>
Alexandre Lision745e4d62015-03-22 20:03:10 -040039
40#import "AppDelegate.h"
Alexandre Lision34607032016-02-08 16:16:49 -050041#import "Constants.h"
42#import "views/NSColor+RingTheme.h"
Alexandre Lision745e4d62015-03-22 20:03:10 -040043
Alexandre Lision08abfac2015-09-22 12:20:51 -040044@implementation RingWizardWC {
Alexandre Lision54187a22016-04-04 09:45:52 -040045
46
47 __unsafe_unretained IBOutlet NSButton* photoView;
Alexandre Lision33942092016-02-03 12:19:09 -050048 __unsafe_unretained IBOutlet NSTextField* nicknameField;
49 __unsafe_unretained IBOutlet NSProgressIndicator* progressBar;
50 __unsafe_unretained IBOutlet NSTextField* indicationLabel;
51 __unsafe_unretained IBOutlet NSButton* createButton;
52 __unsafe_unretained IBOutlet NSButton* showCustomCertsButton;
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040053 IBOutlet NSView *securityContainer;
54
Alexandre Lision34607032016-02-08 16:16:49 -050055 __unsafe_unretained IBOutlet NSButton* shareButton;
Alexandre Lision33942092016-02-03 12:19:09 -050056 __unsafe_unretained IBOutlet NSSecureTextField* passwordField;
57 __unsafe_unretained IBOutlet NSView* pvkContainer;
58 __unsafe_unretained IBOutlet NSPathControl* certificatePathControl;
59 __unsafe_unretained IBOutlet NSPathControl* caListPathControl;
60 __unsafe_unretained IBOutlet NSPathControl* pvkPathControl;
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040061 BOOL isExpanded;
Alexandre Lision08abfac2015-09-22 12:20:51 -040062 Account* accountToCreate;
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040063}
64
Alexandre Lision08abfac2015-09-22 12:20:51 -040065NSInteger const PVK_PASSWORD_TAG = 0;
66NSInteger const NICKNAME_TAG = 1;
Alexandre Lision745e4d62015-03-22 20:03:10 -040067
68- (void)windowDidLoad {
69 [super windowDidLoad];
70
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040071 [passwordField setTag:PVK_PASSWORD_TAG];
Alexandre Lision33942092016-02-03 12:19:09 -050072 [nicknameField setTag:NICKNAME_TAG];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040073
74 isExpanded = false;
Alexandre Lision34607032016-02-08 16:16:49 -050075 [self.window setBackgroundColor:[NSColor ringGreyHighlight]];
76
77 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
Alexandre Lision76d59692016-01-20 18:06:05 -050078
79 if(![appDelegate checkForRingAccount]) {
Alexandre Lision34607032016-02-08 16:16:49 -050080 accountToCreate = AccountModel::instance().add(QString::fromNSString(NSFullUserName()), Account::Protocol::RING);
Alexandre Lision54187a22016-04-04 09:45:52 -040081
Alexandre Lision33942092016-02-03 12:19:09 -050082 [nicknameField setStringValue:NSFullUserName()];
Alexandre Lision34607032016-02-08 16:16:49 -050083 [self controlTextDidChange:[NSNotification notificationWithName:@"PlaceHolder" object:nicknameField]];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040084 }
85
86 [caListPathControl setDelegate:self];
87 [certificatePathControl setDelegate:self];
88 [pvkPathControl setDelegate:self];
Alexandre Lision54187a22016-04-04 09:45:52 -040089
90 NSData* imgData = [[[ABAddressBook sharedAddressBook] me] imageData];
91 if (imgData != nil) {
92 [photoView setImage:[[NSImage alloc] initWithData:imgData]];
93 } else
94 [photoView setImage:[NSImage imageNamed:@"default_user_icon"]];
95
96 [photoView setWantsLayer: YES];
97 photoView.layer.cornerRadius = photoView.frame.size.width / 2;
98 photoView.layer.masksToBounds = YES;
Alexandre Lision745e4d62015-03-22 20:03:10 -040099}
100
Alexandre Lision745e4d62015-03-22 20:03:10 -0400101- (void) displayHash:(NSString* ) hash
102{
Alexandre Lision33942092016-02-03 12:19:09 -0500103 [nicknameField setFrameSize:NSMakeSize(400, nicknameField.frame.size.height)];
104 [nicknameField setStringValue:hash];
105 [nicknameField setEditable:NO];
106 [nicknameField setHidden:NO];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400107
Alexandre Lision08abfac2015-09-22 12:20:51 -0400108 [showCustomCertsButton setHidden:YES];
109
Alexandre Lision34607032016-02-08 16:16:49 -0500110 [shareButton setHidden:NO];
111 [shareButton sendActionOn:NSLeftMouseDownMask];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400112
113 NSSharingService* emailSharingService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
114
Alexandre Lision34607032016-02-08 16:16:49 -0500115 [createButton setTitle:NSLocalizedString(@"Continue",
116 @"Continue button")];
117 [createButton setAction:@selector(goToApp:)];
118}
Alexandre Lision08abfac2015-09-22 12:20:51 -0400119
Alexandre Lision54187a22016-04-04 09:45:52 -0400120- (IBAction) editPhoto:(id)sender
121{
122 auto pictureTaker = [IKPictureTaker pictureTaker];
123 [pictureTaker beginPictureTakerSheetForWindow:self.window
124 withDelegate:self
125 didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:)
126 contextInfo:nil];
127}
128
129- (void) pictureTakerDidEnd:(IKPictureTaker *) picker
130 returnCode:(NSInteger) code
131 contextInfo:(void*) contextInfo
132{
133 if (auto outputImage = [picker outputImage]) {
134 [photoView setImage:outputImage];
135 } else
136 [photoView setImage:[NSImage imageNamed:@"default_user_icon"]];
137}
138
Alexandre Lision34607032016-02-08 16:16:49 -0500139- (IBAction)shareRingID:(id)sender {
Alexandre Lision54187a22016-04-04 09:45:52 -0400140 auto sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObject:[nicknameField stringValue]]];
Alexandre Lision34607032016-02-08 16:16:49 -0500141 [sharingServicePicker showRelativeToRect:[sender bounds]
142 ofView:sender
143 preferredEdge:NSMinYEdge];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400144}
145
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400146- (IBAction)createRingAccount:(id)sender
147{
Alexandre Lision33942092016-02-03 12:19:09 -0500148 [nicknameField setHidden:YES];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400149 [progressBar setHidden:NO];
Alexandre Lision34607032016-02-08 16:16:49 -0500150 [createButton setHidden:YES];
Alexandre Lision54187a22016-04-04 09:45:52 -0400151 [photoView setHidden:YES];
Alexandre Lision34607032016-02-08 16:16:49 -0500152 [progressBar startAnimation:nil];
Alexandre Lision922380d2015-09-15 10:25:17 -0400153 [indicationLabel setStringValue:NSLocalizedString(@"Just a moment...",
154 @"Indication for user")];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400155
Alexandre Lision54187a22016-04-04 09:45:52 -0400156 if (auto profile = ProfileModel::instance().selectedProfile()) {
157 profile->person()->setFormattedName([[nicknameField stringValue] UTF8String]);
158 QPixmap p;
159 if (p.loadFromData(QByteArray::fromNSData([[photoView image] TIFFRepresentation]))) {
160 profile->person()->setPhoto(QVariant(p));
161 }
162 profile->save();
163 }
164
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400165 QModelIndex qIdx = AccountModel::instance().protocolModel()->selectionModel()->currentIndex();
Alexandre Lision745e4d62015-03-22 20:03:10 -0400166
167 [self setCallback];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400168 if (isExpanded) {
169 // retract panel
170 [self chooseOwnCertificates:nil];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400171 }
Alexandre Lision08abfac2015-09-22 12:20:51 -0400172 [showCustomCertsButton setHidden:YES];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400173
Alexandre Lision08abfac2015-09-22 12:20:51 -0400174 [self performSelector:@selector(saveAccount) withObject:nil afterDelay:1];
Alexandre Lision34607032016-02-08 16:16:49 -0500175 [self registerDefaultPreferences];
Alexandre Lision41981972015-06-04 13:27:33 -0400176}
177
178/**
Alexandre Lision34607032016-02-08 16:16:49 -0500179 * Set default values for preferences
Alexandre Lision41981972015-06-04 13:27:33 -0400180 */
Alexandre Lision34607032016-02-08 16:16:49 -0500181- (void) registerDefaultPreferences
Alexandre Lision41981972015-06-04 13:27:33 -0400182{
Alexandre Lision34607032016-02-08 16:16:49 -0500183 // enable AutoStartup
Alexandre Lision41981972015-06-04 13:27:33 -0400184 LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
185 if (loginItemsRef == nil) return;
Alexandre Lision81c97212015-06-17 15:51:53 -0400186 CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
Alexandre Lision41981972015-06-04 13:27:33 -0400187 LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
188 if (itemRef) CFRelease(itemRef);
Alexandre Lision34607032016-02-08 16:16:49 -0500189
190 // enable Notifications
191 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:Preferences::Notifications];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400192}
193
194- (void) saveAccount
195{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400196 accountToCreate->setUpnpEnabled(YES); // Always active upnp
197 accountToCreate << Account::EditAction::SAVE;
Alexandre Lision745e4d62015-03-22 20:03:10 -0400198}
199
200- (void) setCallback
201{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400202 QObject::connect(&AccountModel::instance(),
Alexandre Lision745e4d62015-03-22 20:03:10 -0400203 &AccountModel::accountStateChanged,
204 [=](Account *account, const Account::RegistrationState state) {
Alexandre Lision1abdf582016-02-09 14:21:19 -0500205 [self.window close];
206 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
207 [appDelegate showMainWindow];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400208 });
209}
210
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400211- (IBAction)chooseOwnCertificates:(NSButton*)sender
212{
213 if (isExpanded) {
214 [securityContainer removeFromSuperview];
215 NSRect frame = [self.window frame];
216 frame.size = CGSizeMake(securityContainer.frame.size.width, frame.size.height - securityContainer.frame.size.height);
217 frame.origin.y = frame.origin.y + securityContainer.frame.size.height;
218 [self.window setFrame:frame display:YES animate:YES];
219 isExpanded = false;
220 [sender setImage:[NSImage imageNamed:@"NSAddTemplate"]];
221 } else {
222 NSRect frame = [self.window frame];
223 frame.size = CGSizeMake(securityContainer.frame.size.width, frame.size.height + securityContainer.frame.size.height);
224 frame.origin.y = frame.origin.y - securityContainer.frame.size.height;
225 [self.window setFrame:frame display:YES animate:YES];
226
227 [securityContainer setFrameOrigin:CGPointMake(0, 50)];
228 [self.window.contentView addSubview:securityContainer];
229 isExpanded = true;
230 [sender setImage:[NSImage imageNamed:@"NSRemoveTemplate"]];
231 }
232}
233
234- (IBAction)goToApp:(id)sender
235{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400236 [self.window close];
Alexandre Lision34607032016-02-08 16:16:49 -0500237 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400238 [appDelegate showMainWindow];
239}
240
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400241#pragma mark - NSPathControl delegate methods
Alexandre Lision745e4d62015-03-22 20:03:10 -0400242
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400243- (IBAction)caListPathControlSingleClick:(id)sender
Alexandre Lision745e4d62015-03-22 20:03:10 -0400244{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400245 NSURL* fileURL;
246 if ([sender isKindOfClass:[NSMenuItem class]]) {
247 fileURL = nil;
248 } else {
249 fileURL = [[sender clickedPathComponentCell] URL];
250 }
251 [self->caListPathControl setURL:fileURL];
252 accountToCreate->setTlsCaListCertificate([[fileURL path] UTF8String]);
253
254}
255
256- (IBAction)certificatePathControlSingleClick:(id)sender
257{
258 NSURL* fileURL;
259 if ([sender isKindOfClass:[NSMenuItem class]]) {
260 fileURL = nil;
261 } else {
262 fileURL = [[sender clickedPathComponentCell] URL];
263 }
264 [self->certificatePathControl setURL:fileURL];
265 accountToCreate->setTlsCertificate([[fileURL path] UTF8String]);
266
Alexandre Lision54187a22016-04-04 09:45:52 -0400267 if (auto cert = accountToCreate->tlsCertificate()) {
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400268 [pvkContainer setHidden:!cert->requirePrivateKey()];
269 } else {
270 [pvkContainer setHidden:YES];
271 }
272
273}
274
275- (IBAction)pvkFilePathControlSingleClick:(id)sender
276{
277 NSURL* fileURL;
278 if ([sender isKindOfClass:[NSMenuItem class]]) {
279 fileURL = nil;
280 } else {
281 fileURL = [[sender clickedPathComponentCell] URL];
282 }
283 [self->pvkPathControl setURL:fileURL];
284 accountToCreate->setTlsPrivateKey([[fileURL path] UTF8String]);
285
286 if(accountToCreate->tlsCertificate()->requirePrivateKeyPassword()) {
287 [passwordField setHidden:NO];
288 } else {
289 [passwordField setHidden:YES];
290 }
291}
292
293/*
294 Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
295 */
296- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
297{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400298 [openPanel setAllowsMultipleSelection:NO];
299 [openPanel setCanChooseDirectories:NO];
300 [openPanel setCanChooseFiles:YES];
301 [openPanel setResolvesAliases:YES];
302
303 if(pathControl == caListPathControl) {
304 [openPanel setTitle:NSLocalizedString(@"Choose a CA list", @"Open panel title")];
305 } else if (pathControl == certificatePathControl) {
306 [openPanel setTitle:NSLocalizedString(@"Choose a certificate", @"Open panel title")];
307 } else {
308 [openPanel setTitle:NSLocalizedString(@"Choose a private key file", @"Open panel title")];
309 }
310
311 [openPanel setPrompt:NSLocalizedString(@"Choose", @"Open panel prompt for 'Choose a file'")];
312 [openPanel setDelegate:self];
313}
314
315- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
316{
317 NSMenuItem *item;
318 if(pathControl == caListPathControl) {
Alexandre Lision7f01b072015-09-15 14:57:05 -0400319 item = [menu addItemWithTitle:NSLocalizedString(@"Remove value", @"Contextual menu entry")
320 action:@selector(caListPathControlSingleClick:) keyEquivalent:@""];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400321 } else if (pathControl == certificatePathControl) {
Alexandre Lision7f01b072015-09-15 14:57:05 -0400322 item = [menu addItemWithTitle:NSLocalizedString(@"Remove value", @"Contextual menu entry")
323 action:@selector(certificatePathControlSingleClick:) keyEquivalent:@""];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400324 } else {
Alexandre Lision7f01b072015-09-15 14:57:05 -0400325 item = [menu addItemWithTitle:NSLocalizedString(@"Remove value", @"Contextual menu entry")
326 action:@selector(pvkFilePathControlSingleClick:) keyEquivalent:@""];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400327 }
328 [item setTarget:self]; // or whatever target you want
329}
330
331#pragma mark - NSOpenSavePanelDelegate delegate methods
332
333- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
334{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400335 return YES;
336}
337
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400338#pragma mark - NSTextFieldDelegate methods
339
340-(void)controlTextDidChange:(NSNotification *)notif
Alexandre Lision745e4d62015-03-22 20:03:10 -0400341{
Alexandre Lision33942092016-02-03 12:19:09 -0500342 NSTextField* textField = [notif object];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400343 if (textField.tag == PVK_PASSWORD_TAG) {
344 accountToCreate->setTlsPassword([textField.stringValue UTF8String]);
345 return;
346 }
347
348 // else it is NICKNAME_TAG field
Alexandre Lision34607032016-02-08 16:16:49 -0500349 NSString* alias = textField.stringValue;
350 if ([alias isEqualToString:@""]) {
351 alias = NSLocalizedString(@"Unknown", @"Name used when user leave field empty");
352 }
353 accountToCreate->setAlias([alias UTF8String]);
354 accountToCreate->setDisplayName([alias UTF8String]);
Alexandre Lision745e4d62015-03-22 20:03:10 -0400355}
356
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400357# pragma NSWindowDelegate methods
Alexandre Lision745e4d62015-03-22 20:03:10 -0400358
359- (void)windowWillClose:(NSNotification *)notification
360{
Alexandre Lision34607032016-02-08 16:16:49 -0500361 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
Alexandre Lision76d59692016-01-20 18:06:05 -0500362 if ([appDelegate checkForRingAccount]) {
363 [appDelegate showMainWindow];
364 }
Alexandre Lision745e4d62015-03-22 20:03:10 -0400365}
366
367@end