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"