Finish afscell implementation work
[openafs.git] / src / platform / DARWIN / afscell / afscellPane.m
1 //
2 //  afscellPane.m
3 //  afscell
4 //
5 //  Created by David Botsch on 10/23/07.
6 //  Further developed by Toby Blake, April-May 2008
7 //
8
9 #import "afscellPane.h"
10
11 @implementation afscellPane
12
13 #pragma mark string constants
14 NSString *fileReadThisCell=@"/private/var/db/openafs/etc/ThisCell";
15 NSString *fileReadCellAlias=@"/private/var/db/openafs/etc/CellAlias";
16 NSString *fileWriteThisCell=@"/private/tmp/org.OpenAFS.Install.ThisCell";
17 NSString *fileWriteCellAlias=@"/private/tmp/org.OpenAFS.Install.CellAlias";
18
19 #pragma mark private methods
20 /* check line of CellAlias provided for Cell name, if matches, returns alias in third parameter */
21 - (BOOL)_cellInCellAliasLine:(NSString *)line cellName:(NSString *)cell intoAlias:(NSString **)alias
22 {
23         NSCharacterSet *alphaNum = [NSCharacterSet alphanumericCharacterSet];
24         NSScanner *cellScanner = [NSScanner scannerWithString:line];
25         if (![cellScanner scanUpToString:cell intoString:nil])
26         {
27                 [cellScanner scanString:cell intoString:nil];
28                 /* need to make sure cell name is followed by whitespace */
29                 if (![cellScanner scanUpToCharactersFromSet:alphaNum intoString:nil])
30                 {
31                         /* we have a match */
32                         /* get rest of string */
33                         [cellScanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:alias];
34                         return YES;
35                 }       
36         }
37         return NO;
38 }
39
40 /* writes supplied line (plus newline) to string */
41 - (void)_appendCellAliasLine:(NSString *)line toString:(NSMutableString *)outString
42 {
43         [outString appendString:line];
44         [outString appendFormat:@"\n"];
45 }
46
47 /* writes supplied cell and alias, separated by space (plus newline at end) to string */
48 - (void)_appendNewCellAliasLine:(NSString *)cell aliasName:(NSString *)alias toString:(NSMutableString *)outString
49 {
50         [outString appendString:cell];
51         [outString appendFormat:@" "];
52         [outString appendString:alias];
53         [outString appendFormat:@"\n"];
54 }
55
56 /* displays (slightly) customisable alert */
57 /* we don't use this method any more, but I'll leave it in just in case */
58 - (BOOL) _continueAlert:(NSString *)message cancel:(BOOL)cancelButton
59 {
60         BOOL returnValue = NO;
61         NSAlert *alert = [[NSAlert alloc] init];
62         [alert addButtonWithTitle:@"OK"];
63         (cancelButton) && [alert addButtonWithTitle:@"Cancel"];
64         [alert setMessageText:message];
65         [alert setAlertStyle:NSWarningAlertStyle];
66         
67         if ([alert runModal] == NSAlertFirstButtonReturn)
68         {
69                 returnValue= YES;
70         }
71         [alert release];
72         return returnValue;
73 }
74
75 /* displays (slightly) customisable alert as a more attractive panel than _continueAlert above*/
76 - (BOOL) _continueAlertPanel:(NSString *)message titleText:(NSString *)title firstButtonText:(NSString *)button1 secondButtonText:(NSString *)button2 
77 {
78         if (NSRunInformationalAlertPanel(title, message, button1, button2, nil)
79                 == NSAlertDefaultReturn)
80         {
81                 return YES;
82         }
83         return NO;
84 }
85
86 - (BOOL) _validateStringWord:(NSString *)aString
87 {
88         /* basic string validation to check it's got something in it, doesn't have whitespace or newline */
89         if (aString == nil || [aString length] == 0)
90         {
91                 return NO;
92         }
93
94         if (([aString rangeOfString:@"\n"].location != NSNotFound) ||
95                 ([aString rangeOfString:@"\t"].location != NSNotFound) ||
96                 ([aString rangeOfString:@" "].location != NSNotFound))
97         {
98                 return NO;
99         }
100         return YES;
101 }
102
103 - (BOOL) _validateCellString:(NSString *)cellString
104 {
105         if (![self _validateStringWord:cellString])
106         {
107                 return NO;
108         }
109
110         /* make sure it's in internet domain style, i.e. alphanum.alphanum */
111         NSCharacterSet *alphaNum = [NSCharacterSet alphanumericCharacterSet];
112         NSScanner *cellScanner = [NSScanner scannerWithString:cellString];
113         
114         /* first 'word' */
115         if (![cellScanner scanCharactersFromSet:alphaNum intoString:nil])
116         {
117                 return NO;
118         }
119
120         /* anything that follows must be iteration of '.word' */
121         while (![cellScanner isAtEnd])
122         {
123                 if (![cellScanner scanString:@"." intoString:nil])
124                 {
125                         return NO;
126                 }
127                 if (![cellScanner scanCharactersFromSet:alphaNum intoString:nil])
128                 {
129                         return NO;
130                 }               
131         }
132         
133         return YES;
134 }
135
136 - (BOOL) _validateAliasString:(NSString *)aliasString
137 {
138         if (![self _validateStringWord:aliasString])
139         {
140                 return NO;
141         }
142
143         /* make sure it's alpha-numeric */
144         NSCharacterSet *alphaNum = [NSCharacterSet alphanumericCharacterSet];
145         NSScanner *aliasScanner = [NSScanner scannerWithString:aliasString];
146
147         if (![aliasScanner scanCharactersFromSet:alphaNum intoString:nil])
148         {
149                 return NO;
150         }
151         /* if there's nothing but alpha-numeric, we should be at end */
152         if (![aliasScanner isAtEnd])
153         {
154                 return NO;
155         }
156         
157         return YES;
158 }
159
160 #pragma mark InstallerPane overrides
161 - (NSString *)title
162 {
163         return [[NSBundle bundleForClass:[self class]] localizedStringForKey:@"PaneTitle" value:nil table:nil];
164 }
165
166
167 /* called when user enters pane */
168 - (BOOL)didEnterPane:(InstallerSectionDirection)dir
169 {
170         /* get any existing values from ThisCell and CellAlias files */
171         NSString *readStrCellFile = [NSString stringWithContentsOfFile:fileReadThisCell encoding:NSASCIIStringEncoding error:nil];
172         NSString *readStrAliasFile = [NSString stringWithContentsOfFile:fileReadCellAlias encoding:NSASCIIStringEncoding error:nil];
173
174         /* drop out now if no ThisCell */
175         if (readStrCellFile == nil)
176         {
177                 return YES;
178         }
179
180         NSString *cellString = @"";
181         NSString *aliasString = @"";
182
183         /* we only want the first line from ThisCell */
184         NSScanner *cellFileScanner = [NSScanner scannerWithString:readStrCellFile];
185
186         /* get value, removing any trailing whitespace */
187         [cellFileScanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:&cellString];
188
189         /* set Cell value in pane */
190         [ThisCell setStringValue:cellString];
191
192         /* drop out now if no CellAlias file */
193         if (readStrAliasFile == nil)
194         {
195                 return YES;
196         }
197         
198         /* now find our local cell in the alias file */
199         NSScanner *lineScanner = [NSScanner scannerWithString:readStrAliasFile];
200         NSString *line;
201
202         /* get a line at a time, and check for Cell name */
203         while([lineScanner scanUpToString:@"\n" intoString:&line])
204         {
205                 [self _cellInCellAliasLine:line cellName:cellString intoAlias:&aliasString];
206                 [lineScanner scanString:@"\n" intoString:nil];
207         }
208
209         /* set Alias value in pane */
210         [CellAlias setStringValue:aliasString];
211
212         return YES;
213 }
214
215 /* called when user clicks "Continue" -- return value indicates if application should exit pane */
216 - (BOOL)shouldExitPane:(InstallerSectionDirection)dir
217 {
218         if(InstallerDirectionForward == dir)
219         {
220                 NSString * userName = NSUserName();
221
222                 /* Update ThisCell and CellAlias files with input */
223                 NSString * newStrCell = [ThisCell stringValue];
224                 NSString * newStrAlias = [CellAlias stringValue];
225
226                 if ([newStrCell length] == 0)
227                 {
228                         return [self _continueAlertPanel:@"No local cell value specified.  Proceed with empty value?" titleText:@"No Local Cell" firstButtonText:@"Continue" secondButtonText:@"Cancel"];
229                 }
230                 
231                 /* do some validation on cell string */
232                 if (![self _validateCellString:newStrCell])
233                 {
234                         [self _continueAlertPanel:@"Invalid local cell name: value should be a complete Internet domain-style name (for example, \"abc.com\")" titleText:@"Invalid Cell Name" firstButtonText:@"OK" secondButtonText:nil];
235                         return NO;
236                 }
237                 
238                 /* write value to ThisCell file */
239                 
240                 /* add username to file name */
241                 NSMutableString * fileWriteThisCellUname = [NSMutableString stringWithCapacity:0];
242                 [fileWriteThisCellUname appendString:fileWriteThisCell];
243                 [fileWriteThisCellUname appendFormat:@"."];
244                 [fileWriteThisCellUname appendString:userName];
245
246                 NSMutableString * errorString = [NSMutableString stringWithCapacity:0];
247
248                 NSMutableString * cellString = [NSMutableString stringWithCapacity:0];
249                 [cellString appendString:newStrCell];
250                 [cellString appendFormat:@"\n"];
251                 if (![cellString writeToFile:fileWriteThisCellUname atomically:YES encoding:NSASCIIStringEncoding error:nil])
252                 {
253                         [errorString setString:@"Could not write file: "];
254                         [errorString appendString:fileWriteThisCellUname];
255                         [errorString appendFormat:@"  Continue?"];
256                         if (![self _continueAlertPanel:errorString titleText:@"File Error" firstButtonText:@"Continue" secondButtonText:@"Cancel"])
257                         {
258                                 return NO;
259                         }
260                 }
261
262                 if ([newStrAlias length] != 0)
263                 {
264                         /* do some validation on alias string */
265                         if (![self _validateAliasString:newStrAlias])
266                         {
267                                 [self _continueAlertPanel:@"Invalid alias: value should be alpha-numeric string" titleText:@"Invalid Alias" firstButtonText:@"OK" secondButtonText:nil];
268                                 return NO;
269                         }
270                 
271                         BOOL processedAlias = NO;
272                 
273                         /* read in alias file */
274                         NSString *readStrAliasFile = [NSString stringWithContentsOfFile:fileReadCellAlias encoding:NSASCIIStringEncoding error:nil];
275
276                         /* string to build up for writing out to file */
277                         NSMutableString * aliasString = [NSMutableString stringWithCapacity:0];
278
279                         if (readStrAliasFile != nil)
280                         {
281                                 /* read in a line at a time */
282                                 NSScanner *lineScanner = [NSScanner scannerWithString:readStrAliasFile];
283                                 NSString *line;                                 
284                                 NSString *alias = @"";
285
286                                 while([lineScanner scanUpToString:@"\n" intoString:&line])
287                                 {
288                                         /* check to see if we already have an alias for local cell */
289                                         if ([self _cellInCellAliasLine:line cellName:newStrCell intoAlias:&alias])
290                                         {
291                                                 /* we have a match */
292                                                 if ([alias isEqualToString:newStrAlias])
293                                                 {
294                                                         /* write line as-is */
295                                                         [self _appendCellAliasLine:line toString:aliasString];
296                                                 }
297                                                 else
298                                                 {
299                                                         /* write new cell-alias entry in place */
300                                                         [self _appendNewCellAliasLine:newStrCell aliasName:newStrAlias toString:aliasString];
301                                                 }
302                                                 processedAlias = YES;
303                                         }       
304                                         else
305                                         {
306                                                 /* write line as-is */
307                                                 [self _appendCellAliasLine:line toString:aliasString];
308                                         }
309                                         [lineScanner scanString:@"\n" intoString:nil];
310                                 }
311                         }
312                         if (!processedAlias)
313                         {
314                                 /* if we haven't written our line yet, append to end */
315                                 [self _appendNewCellAliasLine:newStrCell aliasName:newStrAlias toString:aliasString];
316                         }
317
318                         /* add username to file name */
319                         NSMutableString * fileWriteCellAliasUname = [NSMutableString stringWithCapacity:0];
320                         [fileWriteCellAliasUname appendString:fileWriteCellAlias];
321                         [fileWriteCellAliasUname appendFormat:@"."];
322                         [fileWriteCellAliasUname appendString:userName];
323                         
324                         if (![aliasString writeToFile:fileWriteCellAliasUname atomically:YES encoding:NSASCIIStringEncoding error:nil])
325                         {
326                                 [errorString setString:@"Could not write file: "];
327                                 [errorString appendString:fileWriteCellAliasUname];
328                                 [errorString appendFormat:@"  Continue?"];
329                                 if (![self _continueAlertPanel:errorString titleText:@"File Error" firstButtonText:@"Continue" secondButtonText:@"Cancel"])
330
331                                 {
332                                         return NO;
333                                 }
334                         }
335                 }
336         }
337         return YES;
338 }
339
340 @end
341