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