1 /* $Id: macstore.c,v 1.10 2003/01/18 16:10:21 ben Exp $ */
4 * macstore.c: Macintosh-specific impementation of the interface
11 #include <Resources.h>
12 #include <TextUtils.h>
21 #define PUTTY_CREATOR FOUR_CHAR_CODE('pTTY')
22 #define INTERNAL_CREATOR FOUR_CHAR_CODE('pTTI')
23 #define SESS_TYPE FOUR_CHAR_CODE('Sess')
24 #define SEED_TYPE FOUR_CHAR_CODE('Seed')
27 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
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.
34 OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
39 long prefDirID, puttyDirID;
41 error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
42 &prefVRefNum, &prefDirID);
43 if (error != noErr) goto out;
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;
50 *pVRefNum = prefVRefNum;
57 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
61 long puttyDirID, sessDirID;
63 error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
64 if (error != noErr) goto out;
65 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
67 if (error != noErr && error != fnfErr) goto out;
68 error = FSpGetDirID(&sessdir, &sessDirID, makeit);
69 if (error != noErr) goto out;
71 *pVRefNum = puttyVRefNum;
78 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
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) {
94 *idp = pb.dirInfo.ioDrDirID;
100 /* Copy a resource into the current resource file */
101 static OSErr copy_resource(ResType restype, short resid)
106 fprintf(stderr, "getting resource %x, id %d\n", restype, resid);
107 h = GetResource(restype, resid);
109 GetResInfo(h, &resid, &restype, resname);
111 AddResource(h, restype, resid, resname);
112 if (ResError() == noErr)
115 fprintf(stderr, "ResError() == %d\n", ResError());
119 struct write_settings {
125 void *open_settings_w(char const *sessionname) {
126 short sessVRefNum, tmpVRefNum;
127 long sessDirID, tmpDirID;
130 struct write_settings *ws;
132 ws = safemalloc(sizeof *ws);
133 error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
134 if (error != noErr) goto out;
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,
142 if ((error = ResError()) != noErr) goto out;
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;
155 FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
156 if ((error = ResError()) != noErr) goto out;
158 ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
159 if (ws->fd == -1) {error = ResError(); goto out;}
161 /* Set up standard resources. Doesn't matter if these fail. */
162 copy_resource('STR ', -16396);
163 copy_resource('TMPL', TMPL_Int);
169 fatalbox("Failed to open session for write (%d)", error);
172 void write_setting_s(void *handle, char const *key, char const *value) {
173 int fd = *(int *)handle;
179 if (ResError() != noErr)
180 fatalbox("Failed to open saved session (%d)", ResError());
182 error = PtrToHand(value, &h, strlen(value));
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());
194 void write_setting_i(void *handle, char const *key, int value) {
195 int fd = *(int *)handle;
201 if (ResError() != noErr)
202 fatalbox("Failed to open saved session (%d)", ResError());
204 /* XXX assume all systems have the same "int" format */
205 error = PtrToHand(&value, &h, sizeof(int));
207 fatalbox("Failed to allocate memory (%d)", error);
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());
218 void close_settings_w(void *handle) {
219 struct write_settings *ws = handle;
222 CloseResFile(ws->fd);
223 if ((error = ResError()) != noErr)
225 error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
226 if (error != noErr) goto out;
227 error = FSpDelete(&ws->tmpfile);
228 if (error != noErr) goto out;
232 fatalbox("Close of saved session failed (%d)", error);
236 void *open_settings_r(char const *sessionname)
244 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
246 c2pstrcpy(psessionname, sessionname);
247 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
248 if (error != noErr) goto out;
249 return open_settings_r_fsp(&sessfile);
255 void *open_settings_r_fsp(FSSpec *sessfile)
261 fd = FSpOpenResFile(sessfile, fsRdPerm);
262 if (fd == 0) {error = ResError(); goto out;}
264 handle = safemalloc(sizeof *handle);
272 char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
277 if (handle == NULL) goto out;
280 if (ResError() != noErr) goto out;
281 h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
282 if (h == NULL) goto out;
284 len = GetHandleSize(h);
285 if (len + 1 > buflen) goto out;
286 memcpy(buffer, *h, len);
290 if (ResError() != noErr) goto out;
297 int read_setting_i(void *handle, char const *key, int defvalue) {
302 if (handle == NULL) goto out;
305 if (ResError() != noErr) goto out;
306 h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
307 if (h == NULL) goto out;
310 if (ResError() != noErr) goto out;
317 void close_settings_r(void *handle) {
320 if (handle == NULL) return;
323 if (ResError() != noErr)
324 fatalbox("Close of saved session failed (%d)", ResError());
328 void del_settings(char const *sessionname) {
335 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
337 c2pstrcpy(psessionname, sessionname);
338 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
339 if (error != noErr) goto out;
341 error = FSpDelete(&sessfile);
344 fatalbox("Delete session failed (%d)", error);
347 struct enum_settings_state {
353 void *enum_settings_start(void) {
355 struct enum_settings_state *state;
357 state = safemalloc(sizeof(*state));
358 error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
359 if (error != noErr) {
367 char *enum_settings_next(void *handle, char *buffer, int buflen) {
368 struct enum_settings_state *e = handle;
373 if (e == NULL) return NULL;
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 &&
386 p2cstrcpy(buffer, name);
390 void enum_settings_finish(void *handle) {
395 #define SEED_SIZE 512
397 void read_random_seed(noise_consumer_t consumer)
404 long count = SEED_SIZE;
406 if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
408 if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
411 error = FSRead(refnum, &count, buf);
412 if (error != noErr && error != eofErr)
414 (*consumer)(buf, count);
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.
422 void write_random_seed(void *data, int len)
431 if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
434 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
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);
444 } else if (error != noErr) return;
446 if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
447 FSWrite(refnum, &count, data);
456 * c-file-style: "simon"