1 /* $Id: macstore.c,v 1.18 2003/03/29 23:07:55 ben Exp $ */
4 * macstore.c: Macintosh-specific impementation of the interface
11 #include <Resources.h>
12 #include <TextUtils.h>
23 OSErr
FSpGetDirID(FSSpec
*f
, long *idp
, Boolean makeit
);
26 * We store each session as a file in the "PuTTY" sub-directory of the
27 * preferences folder. Each (key,value) pair is stored as a resource.
30 OSErr
get_putty_dir(Boolean makeit
, short *pVRefNum
, long *pDirID
)
35 long prefDirID
, puttyDirID
;
37 error
= FindFolder(kOnSystemDisk
, kPreferencesFolderType
, makeit
,
38 &prefVRefNum
, &prefDirID
);
39 if (error
!= noErr
) goto out
;
41 error
= FSMakeFSSpec(prefVRefNum
, prefDirID
, "\pPuTTY", &puttydir
);
42 if (error
!= noErr
&& error
!= fnfErr
) goto out
;
43 error
= FSpGetDirID(&puttydir
, &puttyDirID
, makeit
);
44 if (error
!= noErr
) goto out
;
46 *pVRefNum
= prefVRefNum
;
53 OSErr
get_session_dir(Boolean makeit
, short *pVRefNum
, long *pDirID
) {
57 long puttyDirID
, sessDirID
;
59 error
= get_putty_dir(makeit
, &puttyVRefNum
, &puttyDirID
);
60 if (error
!= noErr
) goto out
;
61 error
= FSMakeFSSpec(puttyVRefNum
, puttyDirID
, "\pSaved Sessions",
63 if (error
!= noErr
&& error
!= fnfErr
) goto out
;
64 error
= FSpGetDirID(&sessdir
, &sessDirID
, makeit
);
65 if (error
!= noErr
) goto out
;
67 *pVRefNum
= puttyVRefNum
;
74 OSErr
FSpGetDirID(FSSpec
*f
, long *idp
, Boolean makeit
) {
78 pb
.dirInfo
.ioNamePtr
= f
->name
;
79 pb
.dirInfo
.ioVRefNum
= f
->vRefNum
;
80 pb
.dirInfo
.ioDrDirID
= f
->parID
;
81 pb
.dirInfo
.ioFDirIndex
= 0;
82 error
= PBGetCatInfoSync(&pb
);
83 if (error
== fnfErr
&& makeit
)
84 return FSpDirCreate(f
, smSystemScript
, idp
);
85 if (error
!= noErr
) goto out
;
86 if ((pb
.dirInfo
.ioFlAttrib
& ioDirMask
) == 0) {
90 *idp
= pb
.dirInfo
.ioDrDirID
;
96 /* Copy a resource into the current resource file */
97 static OSErr
copy_resource(ResType restype
, short resid
)
102 h
= GetResource(restype
, resid
);
104 GetResInfo(h
, &resid
, &restype
, resname
);
106 AddResource(h
, restype
, resid
, resname
);
107 if (ResError() == noErr
)
113 struct write_settings
{
119 void *open_settings_w(char const *sessionname
) {
126 error
= get_session_dir(kCreateFolder
, &sessVRefNum
, &sessDirID
);
127 if (error
!= noErr
) return NULL
;
129 if (!sessionname
|| !*sessionname
)
130 sessionname
= "Default Settings";
131 c2pstrcpy(psessionname
, sessionname
);
132 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &dstfile
);
133 if (error
== fnfErr
) {
134 FSpCreateResFile(&dstfile
, PUTTY_CREATOR
, SESS_TYPE
, smSystemScript
);
135 if ((error
= ResError()) != noErr
) return NULL
;
136 } else if (error
!= noErr
) return NULL
;
138 return open_settings_w_fsp(&dstfile
);
142 * NB: Destination file must exist.
144 void *open_settings_w_fsp(FSSpec
*dstfile
)
148 struct write_settings
*ws
;
152 ws
= snew(struct write_settings
);
153 ws
->dstfile
= *dstfile
;
155 /* Create a temporary file to save to first. */
156 error
= FindFolder(ws
->dstfile
.vRefNum
, kTemporaryFolderType
,
157 kCreateFolder
, &tmpVRefNum
, &tmpDirID
);
158 if (error
!= noErr
) goto out
;
159 c2pstrcpy(tmpname
, tmpnam(NULL
));
160 error
= FSMakeFSSpec(tmpVRefNum
, tmpDirID
, tmpname
, &ws
->tmpfile
);
161 if (error
!= noErr
&& error
!= fnfErr
) goto out
;
162 if (error
== noErr
) {
163 error
= FSpDelete(&ws
->tmpfile
);
164 if (error
!= noErr
) goto out
;
166 FSpCreateResFile(&ws
->tmpfile
, PUTTY_CREATOR
, SESS_TYPE
, smSystemScript
);
167 if ((error
= ResError()) != noErr
) goto out
;
169 ws
->fd
= FSpOpenResFile(&ws
->tmpfile
, fsWrPerm
);
170 if (ws
->fd
== -1) {error
= ResError(); goto out
;}
172 /* Set up standard resources. Doesn't matter if these fail. */
173 copy_resource('STR ', -16396);
174 copy_resource('TMPL', TMPL_Int
);
180 fatalbox("Failed to open session for write (%d)", error
);
183 void write_setting_s(void *handle
, char const *key
, char const *value
) {
184 int fd
= *(int *)handle
;
191 if (ResError() != noErr
)
192 fatalbox("Failed to open saved session (%d)", ResError());
194 error
= PtrToHand(value
, &h
, strlen(value
));
196 fatalbox("Failed to allocate memory");
197 /* Put the data in a resource. */
198 id
= Unique1ID(FOUR_CHAR_CODE('TEXT'));
199 if (ResError() != noErr
)
200 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
201 c2pstrcpy(pkey
, key
);
202 AddResource(h
, FOUR_CHAR_CODE('TEXT'), id
, pkey
);
203 if (ResError() != noErr
)
204 fatalbox("Failed to add resource %s (%d)", key
, ResError());
207 void write_setting_i(void *handle
, char const *key
, int value
) {
208 int fd
= *(int *)handle
;
215 if (ResError() != noErr
)
216 fatalbox("Failed to open saved session (%d)", ResError());
218 /* XXX assume all systems have the same "int" format */
219 error
= PtrToHand(&value
, &h
, sizeof(int));
221 fatalbox("Failed to allocate memory (%d)", error
);
223 /* Put the data in a resource. */
224 id
= Unique1ID(FOUR_CHAR_CODE('Int '));
225 if (ResError() != noErr
)
226 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
227 c2pstrcpy(pkey
, key
);
228 AddResource(h
, FOUR_CHAR_CODE('Int '), id
, pkey
);
229 if (ResError() != noErr
)
230 fatalbox("Failed to add resource %s (%d)", key
, ResError());
233 void close_settings_w(void *handle
) {
234 struct write_settings
*ws
= handle
;
237 CloseResFile(ws
->fd
);
238 if ((error
= ResError()) != noErr
)
240 error
= FSpExchangeFiles(&ws
->tmpfile
, &ws
->dstfile
);
241 if (error
!= noErr
) goto out
;
242 error
= FSpDelete(&ws
->tmpfile
);
243 if (error
!= noErr
) goto out
;
247 fatalbox("Close of saved session failed (%d)", error
);
251 void *open_settings_r(char const *sessionname
)
259 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
261 if (!sessionname
|| !*sessionname
)
262 sessionname
= "Default Settings";
263 c2pstrcpy(psessionname
, sessionname
);
264 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
265 if (error
!= noErr
) goto out
;
266 return open_settings_r_fsp(&sessfile
);
272 void *open_settings_r_fsp(FSSpec
*sessfile
)
278 fd
= FSpOpenResFile(sessfile
, fsRdPerm
);
279 if (fd
== 0) {error
= ResError(); goto out
;}
289 char *read_setting_s(void *handle
, char const *key
, char *buffer
, int buflen
) {
295 if (handle
== NULL
) goto out
;
298 if (ResError() != noErr
) goto out
;
299 c2pstrcpy(pkey
, key
);
300 h
= Get1NamedResource(FOUR_CHAR_CODE('TEXT'), pkey
);
301 if (h
== NULL
) goto out
;
303 len
= GetHandleSize(h
);
304 if (len
+ 1 > buflen
) goto out
;
305 memcpy(buffer
, *h
, len
);
309 if (ResError() != noErr
) goto out
;
316 int read_setting_i(void *handle
, char const *key
, int defvalue
) {
322 if (handle
== NULL
) goto out
;
325 if (ResError() != noErr
) goto out
;
326 c2pstrcpy(pkey
, key
);
327 h
= Get1NamedResource(FOUR_CHAR_CODE('Int '), pkey
);
328 if (h
== NULL
) goto out
;
331 if (ResError() != noErr
) goto out
;
338 int read_setting_fontspec(void *handle
, const char *name
, FontSpec
*result
)
344 if (!read_setting_s(handle
, name
, tmp
, sizeof(tmp
)))
346 c2pstrcpy(ret
.name
, tmp
);
347 settingname
= dupcat(name
, "Face", NULL
);
348 ret
.face
= read_setting_i(handle
, settingname
, 0);
350 settingname
= dupcat(name
, "Height", NULL
);
351 ret
.size
= read_setting_i(handle
, settingname
, 0);
353 if (ret
.size
== 0) return 0;
358 void write_setting_fontspec(void *handle
, const char *name
, FontSpec font
)
363 p2cstrcpy(tmp
, font
.name
);
364 write_setting_s(handle
, name
, tmp
);
365 settingname
= dupcat(name
, "Face", NULL
);
366 write_setting_i(handle
, settingname
, font
.face
);
368 settingname
= dupcat(name
, "Size", NULL
);
369 write_setting_i(handle
, settingname
, font
.size
);
373 int read_setting_filename(void *handle
, const char *key
, Filename
*result
)
381 if (handle
== NULL
) goto out
;
384 if (ResError() != noErr
) goto out
;
385 c2pstrcpy(pkey
, key
);
386 h
= (AliasHandle
)Get1NamedResource(rAliasType
, pkey
);
387 if (h
== NULL
) goto out
;
388 if ((*h
)->userType
== 'pTTY' && (*h
)->aliasSize
== sizeof(**h
))
389 memset(result
, 0, sizeof(*result
));
391 err
= ResolveAlias(NULL
, h
, &result
->fss
, &changed
);
392 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
393 if ((*h
)->userType
== 'pTTY') {
397 /* Tail of record is pascal string contaning leafname */
398 if (FSpGetDirID(&result
->fss
, &dirid
, FALSE
) != noErr
) goto out
;
399 memcpy(fname
, (char *)*h
+ (*h
)->aliasSize
,
400 GetHandleSize((Handle
)h
) - (*h
)->aliasSize
);
401 err
= FSMakeFSSpec(result
->fss
.vRefNum
, dirid
, fname
,
403 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
406 ReleaseResource((Handle
)h
);
407 if (ResError() != noErr
) goto out
;
414 void write_setting_filename(void *handle
, const char *key
, Filename fn
)
416 int fd
= *(int *)handle
;
423 if (ResError() != noErr
)
424 fatalbox("Failed to open saved session (%d)", ResError());
426 if (filename_is_null(fn
)) {
427 /* Generate a special "null" alias */
428 h
= (AliasHandle
)NewHandle(sizeof(**h
));
430 fatalbox("Failed to create fake alias");
431 (*h
)->userType
= 'pTTY';
432 (*h
)->aliasSize
= sizeof(**h
);
434 error
= NewAlias(NULL
, &fn
.fss
, &h
);
435 if (error
== fnfErr
) {
437 * NewAlias can't create an alias for a nonexistent file.
438 * Create an alias for the directory, and record the
443 FSMakeFSSpec(fn
.fss
.vRefNum
, fn
.fss
.parID
, NULL
, &tmpfss
);
444 error
= NewAlias(NULL
, &tmpfss
, &h
);
446 fatalbox("Failed to create alias");
447 (*h
)->userType
= 'pTTY';
448 SetHandleSize((Handle
)h
, (*h
)->aliasSize
+ fn
.fss
.name
[0] + 1);
449 if (MemError() != noErr
)
450 fatalbox("Failed to create alias");
451 memcpy((char *)*h
+ (*h
)->aliasSize
, fn
.fss
.name
,
455 fatalbox("Failed to create alias");
457 /* Put the data in a resource. */
458 id
= Unique1ID(rAliasType
);
459 if (ResError() != noErr
)
460 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
461 c2pstrcpy(pkey
, key
);
462 AddResource((Handle
)h
, rAliasType
, id
, pkey
);
463 if (ResError() != noErr
)
464 fatalbox("Failed to add resource %s (%d)", key
, ResError());
467 void close_settings_r(void *handle
) {
470 if (handle
== NULL
) return;
473 if (ResError() != noErr
)
474 fatalbox("Close of saved session failed (%d)", ResError());
478 void del_settings(char const *sessionname
) {
485 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
487 c2pstrcpy(psessionname
, sessionname
);
488 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
489 if (error
!= noErr
) goto out
;
491 error
= FSpDelete(&sessfile
);
494 fatalbox("Delete session failed (%d)", error
);
497 struct enum_settings_state
{
503 void *enum_settings_start(void) {
505 struct enum_settings_state
*state
;
507 state
= safemalloc(sizeof(*state
));
508 error
= get_session_dir(kDontCreateFolder
, &state
->vRefNum
, &state
->dirID
);
509 if (error
!= noErr
) {
517 char *enum_settings_next(void *handle
, char *buffer
, int buflen
) {
518 struct enum_settings_state
*e
= handle
;
523 if (e
== NULL
) return NULL
;
525 pb
.hFileInfo
.ioNamePtr
= name
;
526 pb
.hFileInfo
.ioVRefNum
= e
->vRefNum
;
527 pb
.hFileInfo
.ioDirID
= e
->dirID
;
528 pb
.hFileInfo
.ioFDirIndex
= e
->index
++;
529 error
= PBGetCatInfoSync(&pb
);
530 if (error
!= noErr
) return NULL
;
531 } while (!((pb
.hFileInfo
.ioFlAttrib
& ioDirMask
) == 0 &&
532 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
== PUTTY_CREATOR
&&
533 pb
.hFileInfo
.ioFlFndrInfo
.fdType
== SESS_TYPE
&&
536 p2cstrcpy(buffer
, name
);
540 void enum_settings_finish(void *handle
) {
545 #define SEED_SIZE 512
547 void read_random_seed(noise_consumer_t consumer
)
554 long count
= SEED_SIZE
;
556 if (get_putty_dir(kDontCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
558 if (HOpenDF(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed", fsRdPerm
,
561 error
= FSRead(refnum
, &count
, buf
);
562 if (error
!= noErr
&& error
!= eofErr
)
564 (*consumer
)(buf
, count
);
569 * We don't bother with the usual FSpExchangeFiles dance here because
570 * it doesn't really matter if the old random seed gets lost.
572 void write_random_seed(void *data
, int len
)
581 if (get_putty_dir(kCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
584 error
= FSMakeFSSpec(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed",
586 if (error
== fnfErr
) {
587 /* Set up standard resources */
588 FSpCreateResFile(&dstfile
, INTERNAL_CREATOR
, SEED_TYPE
, smRoman
);
589 refnum
= FSpOpenResFile(&dstfile
, fsWrPerm
);
590 if (ResError() == noErr
) {
591 copy_resource('STR ', -16397);
592 CloseResFile(refnum
);
594 } else if (error
!= noErr
) return;
596 if (FSpOpenDF(&dstfile
, fsWrPerm
, &refnum
) != noErr
) return;
597 FSWrite(refnum
, &count
, data
);
606 * c-file-style: "simon"