0c4b7799 |
1 | /* $Id: macstore.c,v 1.7 2003/01/08 22:46:12 ben Exp $ */ |
d082ac49 |
2 | |
3 | /* |
4 | * macstore.c: Macintosh-specific impementation of the interface |
5 | * defined in storage.h |
6 | */ |
7 | |
8 | #include <MacTypes.h> |
9 | #include <Folders.h> |
10 | #include <Memory.h> |
11 | #include <Resources.h> |
12 | #include <TextUtils.h> |
13 | |
14 | #include <string.h> |
15 | |
16 | #include "putty.h" |
17 | #include "storage.h" |
ce283213 |
18 | #include "mac.h" |
d082ac49 |
19 | |
20 | #define PUTTY_CREATOR FOUR_CHAR_CODE('pTTY') |
21 | #define SESS_TYPE FOUR_CHAR_CODE('Sess') |
0c4b7799 |
22 | #define SEED_TYPE FOUR_CHAR_CODE('Seed') |
d082ac49 |
23 | |
24 | |
d082ac49 |
25 | OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit); |
26 | |
27 | /* |
28 | * We store each session as a file in the "PuTTY" sub-directory of the |
29 | * preferences folder. Each (key,value) pair is stored as a resource. |
30 | */ |
31 | |
0c4b7799 |
32 | OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID) |
33 | { |
d082ac49 |
34 | OSErr error = noErr; |
35 | short prefVRefNum; |
0c4b7799 |
36 | FSSpec puttydir; |
37 | long prefDirID, puttyDirID; |
d082ac49 |
38 | |
39 | error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit, |
40 | &prefVRefNum, &prefDirID); |
41 | if (error != noErr) goto out; |
42 | |
43 | error = FSMakeFSSpec(prefVRefNum, prefDirID, "\pPuTTY", &puttydir); |
44 | if (error != noErr && error != fnfErr) goto out; |
45 | error = FSpGetDirID(&puttydir, &puttyDirID, makeit); |
46 | if (error != noErr) goto out; |
47 | |
0c4b7799 |
48 | *pVRefNum = prefVRefNum; |
49 | *pDirID = puttyDirID; |
50 | |
51 | out: |
52 | return error; |
53 | } |
54 | |
55 | OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) { |
56 | OSErr error = noErr; |
57 | short puttyVRefNum; |
58 | FSSpec sessdir; |
59 | long puttyDirID, sessDirID; |
60 | |
61 | error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID); |
62 | if (error != noErr) goto out; |
63 | error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions", |
d082ac49 |
64 | &sessdir); |
65 | if (error != noErr && error != fnfErr) goto out; |
66 | error = FSpGetDirID(&sessdir, &sessDirID, makeit); |
67 | if (error != noErr) goto out; |
68 | |
0c4b7799 |
69 | *pVRefNum = puttyVRefNum; |
d082ac49 |
70 | *pDirID = sessDirID; |
71 | |
72 | out: |
73 | return error; |
74 | } |
75 | |
76 | OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) { |
77 | CInfoPBRec pb; |
78 | OSErr error = noErr; |
79 | |
80 | pb.dirInfo.ioNamePtr = f->name; |
81 | pb.dirInfo.ioVRefNum = f->vRefNum; |
82 | pb.dirInfo.ioDrDirID = f->parID; |
83 | pb.dirInfo.ioFDirIndex = 0; |
84 | error = PBGetCatInfoSync(&pb); |
85 | if (error == fnfErr && makeit) |
86 | return FSpDirCreate(f, smSystemScript, idp); |
87 | if (error != noErr) goto out; |
88 | if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) { |
89 | error = dirNFErr; |
90 | goto out; |
91 | } |
92 | *idp = pb.dirInfo.ioDrDirID; |
93 | |
94 | out: |
95 | return error; |
96 | } |
97 | |
98 | struct write_settings { |
99 | int fd; |
100 | FSSpec tmpfile; |
101 | FSSpec dstfile; |
102 | }; |
103 | |
104 | void *open_settings_w(char *sessionname) { |
105 | short sessVRefNum, tmpVRefNum; |
106 | long sessDirID, tmpDirID; |
d082ac49 |
107 | OSErr error; |
108 | Str255 psessionname; |
109 | struct write_settings *ws; |
110 | |
111 | ws = safemalloc(sizeof *ws); |
112 | error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID); |
113 | if (error != noErr) goto out; |
114 | |
115 | c2pstrcpy(psessionname, sessionname); |
116 | error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &ws->dstfile); |
117 | if (error != noErr && error != fnfErr) goto out; |
118 | if (error == fnfErr) { |
119 | FSpCreateResFile(&ws->dstfile, PUTTY_CREATOR, SESS_TYPE, |
120 | smSystemScript); |
121 | if ((error = ResError()) != noErr) goto out; |
122 | } |
123 | |
124 | /* Create a temporary file to save to first. */ |
125 | error = FindFolder(sessVRefNum, kTemporaryFolderType, kCreateFolder, |
126 | &tmpVRefNum, &tmpDirID); |
127 | if (error != noErr) goto out; |
128 | error = FSMakeFSSpec(tmpVRefNum, tmpDirID, psessionname, &ws->tmpfile); |
129 | if (error != noErr && error != fnfErr) goto out; |
130 | if (error == noErr) { |
131 | error = FSpDelete(&ws->tmpfile); |
132 | if (error != noErr) goto out; |
133 | } |
134 | FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript); |
135 | if ((error = ResError()) != noErr) goto out; |
136 | |
137 | ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm); |
138 | if (ws->fd == -1) {error = ResError(); goto out;} |
139 | |
140 | return ws; |
141 | |
142 | out: |
143 | safefree(ws); |
144 | fatalbox("Failed to open session for write (%d)", error); |
145 | } |
146 | |
147 | void write_setting_s(void *handle, char *key, char *value) { |
148 | int fd = *(int *)handle; |
149 | Handle h; |
150 | int id; |
803efcdf |
151 | OSErr error; |
d082ac49 |
152 | |
153 | UseResFile(fd); |
154 | if (ResError() != noErr) |
155 | fatalbox("Failed to open saved session (%d)", ResError()); |
156 | |
157 | error = PtrToHand(value, &h, strlen(value)); |
158 | if (error != noErr) |
159 | fatalbox("Failed to allocate memory"); |
160 | /* Put the data in a resource. */ |
161 | id = Unique1ID(FOUR_CHAR_CODE('TEXT')); |
162 | if (ResError() != noErr) |
163 | fatalbox("Failed to get ID for resource %s (%d)", key, ResError()); |
164 | addresource(h, FOUR_CHAR_CODE('TEXT'), id, key); |
165 | if (ResError() != noErr) |
166 | fatalbox("Failed to add resource %s (%d)", key, ResError()); |
167 | } |
168 | |
169 | void write_setting_i(void *handle, char *key, int value) { |
170 | int fd = *(int *)handle; |
171 | Handle h; |
172 | int id; |
173 | OSErr error; |
174 | |
175 | UseResFile(fd); |
176 | if (ResError() != noErr) |
177 | fatalbox("Failed to open saved session (%d)", ResError()); |
178 | |
179 | /* XXX assume all systems have the same "int" format */ |
180 | error = PtrToHand(&value, &h, sizeof(int)); |
181 | if (error != noErr) |
182 | fatalbox("Failed to allocate memory (%d)", error); |
183 | |
184 | /* Put the data in a resource. */ |
185 | id = Unique1ID(FOUR_CHAR_CODE('Int ')); |
186 | if (ResError() != noErr) |
187 | fatalbox("Failed to get ID for resource %s (%d)", key, ResError()); |
188 | addresource(h, FOUR_CHAR_CODE('Int '), id, key); |
189 | if (ResError() != noErr) |
190 | fatalbox("Failed to add resource %s (%d)", key, ResError()); |
191 | } |
192 | |
193 | void close_settings_w(void *handle) { |
194 | struct write_settings *ws = handle; |
195 | OSErr error; |
196 | |
197 | CloseResFile(ws->fd); |
198 | if ((error = ResError()) != noErr) |
199 | goto out; |
200 | error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile); |
201 | if (error != noErr) goto out; |
202 | error = FSpDelete(&ws->tmpfile); |
203 | if (error != noErr) goto out; |
204 | return; |
205 | |
206 | out: |
207 | fatalbox("Close of saved session failed (%d)", error); |
208 | safefree(handle); |
209 | } |
210 | |
ce283213 |
211 | void *open_settings_r(char *sessionname) |
212 | { |
d082ac49 |
213 | short sessVRefNum; |
214 | long sessDirID; |
215 | FSSpec sessfile; |
216 | OSErr error; |
217 | Str255 psessionname; |
d082ac49 |
218 | |
219 | error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID); |
220 | |
221 | c2pstrcpy(psessionname, sessionname); |
222 | error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile); |
223 | if (error != noErr) goto out; |
ce283213 |
224 | return open_settings_r_fsp(&sessfile); |
225 | |
226 | out: |
227 | return NULL; |
228 | } |
229 | |
230 | void *open_settings_r_fsp(FSSpec *sessfile) |
231 | { |
232 | OSErr error; |
233 | int fd; |
234 | int *handle; |
235 | |
236 | fd = FSpOpenResFile(sessfile, fsRdPerm); |
d082ac49 |
237 | if (fd == 0) {error = ResError(); goto out;} |
238 | |
239 | handle = safemalloc(sizeof *handle); |
240 | *handle = fd; |
241 | return handle; |
242 | |
243 | out: |
244 | return NULL; |
245 | } |
246 | |
d082ac49 |
247 | char *read_setting_s(void *handle, char *key, char *buffer, int buflen) { |
248 | int fd; |
249 | Handle h; |
086efcde |
250 | size_t len; |
d082ac49 |
251 | |
252 | if (handle == NULL) goto out; |
253 | fd = *(int *)handle; |
254 | UseResFile(fd); |
255 | if (ResError() != noErr) goto out; |
256 | h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key); |
257 | if (h == NULL) goto out; |
258 | |
086efcde |
259 | len = GetHandleSize(h); |
260 | if (len + 1 > buflen) goto out; |
261 | memcpy(buffer, *h, len); |
262 | buffer[len] = '\0'; |
263 | |
d082ac49 |
264 | ReleaseResource(h); |
265 | if (ResError() != noErr) goto out; |
266 | return buffer; |
267 | |
268 | out: |
269 | return NULL; |
270 | } |
271 | |
272 | int read_setting_i(void *handle, char *key, int defvalue) { |
273 | int fd; |
274 | Handle h; |
d082ac49 |
275 | int value; |
276 | |
277 | if (handle == NULL) goto out; |
278 | fd = *(int *)handle; |
279 | UseResFile(fd); |
280 | if (ResError() != noErr) goto out; |
281 | h = get1namedresource(FOUR_CHAR_CODE('Int '), key); |
282 | if (h == NULL) goto out; |
283 | value = *(int *)*h; |
284 | ReleaseResource(h); |
285 | if (ResError() != noErr) goto out; |
286 | return value; |
287 | |
288 | out: |
289 | return defvalue; |
290 | } |
291 | |
292 | void close_settings_r(void *handle) { |
293 | int fd; |
294 | |
295 | if (handle == NULL) return; |
296 | fd = *(int *)handle; |
297 | CloseResFile(fd); |
298 | if (ResError() != noErr) |
299 | fatalbox("Close of saved session failed (%d)", ResError()); |
300 | safefree(handle); |
301 | } |
302 | |
303 | void del_settings(char *sessionname) { |
304 | OSErr error; |
305 | FSSpec sessfile; |
306 | short sessVRefNum; |
307 | long sessDirID; |
308 | Str255 psessionname; |
309 | |
310 | error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID); |
311 | |
312 | c2pstrcpy(psessionname, sessionname); |
313 | error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile); |
314 | if (error != noErr) goto out; |
315 | |
316 | error = FSpDelete(&sessfile); |
317 | return; |
318 | out: |
319 | fatalbox("Delete session failed (%d)", error); |
320 | } |
321 | |
322 | struct enum_settings_state { |
323 | short vRefNum; |
324 | long dirID; |
325 | int index; |
326 | }; |
327 | |
328 | void *enum_settings_start(void) { |
329 | OSErr error; |
330 | struct enum_settings_state *state; |
331 | |
332 | state = safemalloc(sizeof(*state)); |
333 | error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID); |
334 | if (error != noErr) { |
335 | safefree(state); |
336 | return NULL; |
337 | } |
338 | state->index = 1; |
339 | return state; |
340 | } |
341 | |
342 | char *enum_settings_next(void *handle, char *buffer, int buflen) { |
343 | struct enum_settings_state *e = handle; |
344 | CInfoPBRec pb; |
345 | OSErr error = noErr; |
346 | Str255 name; |
347 | |
348 | if (e == NULL) return NULL; |
349 | do { |
350 | pb.hFileInfo.ioNamePtr = name; |
351 | pb.hFileInfo.ioVRefNum = e->vRefNum; |
352 | pb.hFileInfo.ioDirID = e->dirID; |
353 | pb.hFileInfo.ioFDirIndex = e->index++; |
354 | error = PBGetCatInfoSync(&pb); |
355 | if (error != noErr) return NULL; |
356 | } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 && |
357 | pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR && |
358 | pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE && |
359 | name[0] < buflen)); |
360 | |
361 | p2cstrcpy(buffer, name); |
362 | return buffer; |
363 | } |
364 | |
365 | void enum_settings_finish(void *handle) { |
366 | |
367 | safefree(handle); |
368 | } |
369 | |
0c4b7799 |
370 | #define SEED_SIZE 512 |
371 | |
372 | void read_random_seed(noise_consumer_t consumer) |
373 | { |
374 | short puttyVRefNum; |
375 | long puttyDirID; |
376 | OSErr error; |
377 | char buf[SEED_SIZE]; |
378 | short refnum; |
379 | long count = SEED_SIZE; |
380 | |
381 | if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr) |
382 | return; |
383 | if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm, |
384 | &refnum) != noErr) |
385 | return; |
386 | error = FSRead(refnum, &count, buf); |
387 | if (error != noErr && error != eofErr) |
388 | return; |
389 | (*consumer)(buf, count); |
390 | FSClose(refnum); |
391 | } |
392 | |
393 | void write_random_seed(void *data, int len) |
394 | { |
395 | short puttyVRefNum, tmpVRefNum; |
396 | long puttyDirID, tmpDirID; |
397 | OSErr error; |
398 | FSSpec dstfile, tmpfile; |
399 | short refnum; |
400 | long count = len; |
401 | |
402 | if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr) |
403 | return; |
404 | |
405 | error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", |
406 | &dstfile); |
407 | if (error != noErr && error != fnfErr) return; |
408 | |
409 | /* Create a temporary file to save to first. */ |
410 | error = FindFolder(puttyVRefNum, kTemporaryFolderType, kCreateFolder, |
411 | &tmpVRefNum, &tmpDirID); |
412 | if (error != noErr) return; |
413 | error = FSMakeFSSpec(tmpVRefNum, tmpDirID, "\pPuTTY Random Seed", |
414 | &tmpfile); |
415 | if (error != noErr && error != fnfErr) return; |
416 | if (error == noErr) { |
417 | error = FSpDelete(&tmpfile); |
418 | if (error != noErr) return; |
419 | } |
420 | error = FSpCreate(&tmpfile, PUTTY_CREATOR, SEED_TYPE, smRoman); |
421 | if (error != noErr) return; |
422 | |
423 | if (FSpOpenDF(&tmpfile, fsWrPerm, &refnum) != noErr) goto fail; |
424 | |
425 | if (FSWrite(refnum, &count, data) != noErr) goto fail2; |
426 | if (FSClose(refnum) != noErr) goto fail; |
427 | |
428 | if (FSpExchangeFiles(&tmpfile, &dstfile) != noErr) goto fail; |
429 | if (FSpDelete(&tmpfile) != noErr) return; |
430 | |
431 | return; |
432 | |
433 | fail2: |
434 | FSClose(refnum); |
435 | fail: |
436 | FSpDelete(&tmpfile); |
437 | } |
d082ac49 |
438 | |
439 | /* |
440 | * Emacs magic: |
441 | * Local Variables: |
442 | * c-file-style: "simon" |
443 | * End: |
444 | */ |