1 /* $Id: macstore.c,v 1.9 2003/01/18 12:03:28 ben Exp $ */
4 * macstore.c: Macintosh-specific impementation of the interface
11 #include <Resources.h>
12 #include <TextUtils.h>
20 #define PUTTY_CREATOR FOUR_CHAR_CODE('pTTY')
21 #define SESS_TYPE FOUR_CHAR_CODE('Sess')
22 #define SEED_TYPE FOUR_CHAR_CODE('Seed')
25 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
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.
32 OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
37 long prefDirID, puttyDirID;
39 error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
40 &prefVRefNum, &prefDirID);
41 if (error != noErr) goto out;
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;
48 *pVRefNum = prefVRefNum;
55 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
59 long puttyDirID, sessDirID;
61 error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
62 if (error != noErr) goto out;
63 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
65 if (error != noErr && error != fnfErr) goto out;
66 error = FSpGetDirID(&sessdir, &sessDirID, makeit);
67 if (error != noErr) goto out;
69 *pVRefNum = puttyVRefNum;
76 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
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) {
92 *idp = pb.dirInfo.ioDrDirID;
98 struct write_settings {
104 void *open_settings_w(char const *sessionname) {
105 short sessVRefNum, tmpVRefNum;
106 long sessDirID, tmpDirID;
109 struct write_settings *ws;
111 ws = safemalloc(sizeof *ws);
112 error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
113 if (error != noErr) goto out;
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,
121 if ((error = ResError()) != noErr) goto out;
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;
134 FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
135 if ((error = ResError()) != noErr) goto out;
137 ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
138 if (ws->fd == -1) {error = ResError(); goto out;}
144 fatalbox("Failed to open session for write (%d)", error);
147 void write_setting_s(void *handle, char const *key, char const *value) {
148 int fd = *(int *)handle;
154 if (ResError() != noErr)
155 fatalbox("Failed to open saved session (%d)", ResError());
157 error = PtrToHand(value, &h, strlen(value));
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());
169 void write_setting_i(void *handle, char const *key, int value) {
170 int fd = *(int *)handle;
176 if (ResError() != noErr)
177 fatalbox("Failed to open saved session (%d)", ResError());
179 /* XXX assume all systems have the same "int" format */
180 error = PtrToHand(&value, &h, sizeof(int));
182 fatalbox("Failed to allocate memory (%d)", error);
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());
193 void close_settings_w(void *handle) {
194 struct write_settings *ws = handle;
197 CloseResFile(ws->fd);
198 if ((error = ResError()) != noErr)
200 error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
201 if (error != noErr) goto out;
202 error = FSpDelete(&ws->tmpfile);
203 if (error != noErr) goto out;
207 fatalbox("Close of saved session failed (%d)", error);
211 void *open_settings_r(char const *sessionname)
219 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
221 c2pstrcpy(psessionname, sessionname);
222 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
223 if (error != noErr) goto out;
224 return open_settings_r_fsp(&sessfile);
230 void *open_settings_r_fsp(FSSpec *sessfile)
236 fd = FSpOpenResFile(sessfile, fsRdPerm);
237 if (fd == 0) {error = ResError(); goto out;}
239 handle = safemalloc(sizeof *handle);
247 char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
252 if (handle == NULL) goto out;
255 if (ResError() != noErr) goto out;
256 h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
257 if (h == NULL) goto out;
259 len = GetHandleSize(h);
260 if (len + 1 > buflen) goto out;
261 memcpy(buffer, *h, len);
265 if (ResError() != noErr) goto out;
272 int read_setting_i(void *handle, char const *key, int defvalue) {
277 if (handle == NULL) goto out;
280 if (ResError() != noErr) goto out;
281 h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
282 if (h == NULL) goto out;
285 if (ResError() != noErr) goto out;
292 void close_settings_r(void *handle) {
295 if (handle == NULL) return;
298 if (ResError() != noErr)
299 fatalbox("Close of saved session failed (%d)", ResError());
303 void del_settings(char const *sessionname) {
310 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
312 c2pstrcpy(psessionname, sessionname);
313 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
314 if (error != noErr) goto out;
316 error = FSpDelete(&sessfile);
319 fatalbox("Delete session failed (%d)", error);
322 struct enum_settings_state {
328 void *enum_settings_start(void) {
330 struct enum_settings_state *state;
332 state = safemalloc(sizeof(*state));
333 error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
334 if (error != noErr) {
342 char *enum_settings_next(void *handle, char *buffer, int buflen) {
343 struct enum_settings_state *e = handle;
348 if (e == NULL) return NULL;
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 &&
361 p2cstrcpy(buffer, name);
365 void enum_settings_finish(void *handle) {
370 #define SEED_SIZE 512
372 void read_random_seed(noise_consumer_t consumer)
379 long count = SEED_SIZE;
381 if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
383 if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
386 error = FSRead(refnum, &count, buf);
387 if (error != noErr && error != eofErr)
389 (*consumer)(buf, count);
394 * We don't bother with the usual FSpExchangeFiles dance here because
395 * it doesn't really matter if the old random seed gets lost.
397 void write_random_seed(void *data, int len)
406 if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
409 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
412 error = FSpCreate(&dstfile, PUTTY_CREATOR, SEED_TYPE, smRoman);
413 if (error != noErr) return;
415 if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
417 FSWrite(refnum, &count, data);
426 * c-file-style: "simon"