1 /* $Id: macstore.c,v 1.15 2003/02/01 21:44:05 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 c2pstrcpy(psessionname
, sessionname
);
130 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &dstfile
);
131 if (error
== fnfErr
) {
132 FSpCreateResFile(&dstfile
, PUTTY_CREATOR
, SESS_TYPE
, smSystemScript
);
133 if ((error
= ResError()) != noErr
) return NULL
;
134 } else if (error
!= noErr
) return NULL
;
136 return open_settings_w_fsp(&dstfile
);
140 * NB: Destination file must exist.
142 void *open_settings_w_fsp(FSSpec
*dstfile
)
146 struct write_settings
*ws
;
150 ws
= smalloc(sizeof *ws
);
151 ws
->dstfile
= *dstfile
;
153 /* Create a temporary file to save to first. */
154 error
= FindFolder(ws
->dstfile
.vRefNum
, kTemporaryFolderType
,
155 kCreateFolder
, &tmpVRefNum
, &tmpDirID
);
156 if (error
!= noErr
) goto out
;
157 c2pstrcpy(tmpname
, tmpnam(NULL
));
158 error
= FSMakeFSSpec(tmpVRefNum
, tmpDirID
, tmpname
, &ws
->tmpfile
);
159 if (error
!= noErr
&& error
!= fnfErr
) goto out
;
160 if (error
== noErr
) {
161 error
= FSpDelete(&ws
->tmpfile
);
162 if (error
!= noErr
) goto out
;
164 FSpCreateResFile(&ws
->tmpfile
, PUTTY_CREATOR
, SESS_TYPE
, smSystemScript
);
165 if ((error
= ResError()) != noErr
) goto out
;
167 ws
->fd
= FSpOpenResFile(&ws
->tmpfile
, fsWrPerm
);
168 if (ws
->fd
== -1) {error
= ResError(); goto out
;}
170 /* Set up standard resources. Doesn't matter if these fail. */
171 copy_resource('STR ', -16396);
172 copy_resource('TMPL', TMPL_Int
);
178 fatalbox("Failed to open session for write (%d)", error
);
181 void write_setting_s(void *handle
, char const *key
, char const *value
) {
182 int fd
= *(int *)handle
;
188 if (ResError() != noErr
)
189 fatalbox("Failed to open saved session (%d)", ResError());
191 error
= PtrToHand(value
, &h
, strlen(value
));
193 fatalbox("Failed to allocate memory");
194 /* Put the data in a resource. */
195 id
= Unique1ID(FOUR_CHAR_CODE('TEXT'));
196 if (ResError() != noErr
)
197 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
198 addresource(h
, FOUR_CHAR_CODE('TEXT'), id
, key
);
199 if (ResError() != noErr
)
200 fatalbox("Failed to add resource %s (%d)", key
, ResError());
203 void write_setting_i(void *handle
, char const *key
, int value
) {
204 int fd
= *(int *)handle
;
210 if (ResError() != noErr
)
211 fatalbox("Failed to open saved session (%d)", ResError());
213 /* XXX assume all systems have the same "int" format */
214 error
= PtrToHand(&value
, &h
, sizeof(int));
216 fatalbox("Failed to allocate memory (%d)", error
);
218 /* Put the data in a resource. */
219 id
= Unique1ID(FOUR_CHAR_CODE('Int '));
220 if (ResError() != noErr
)
221 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
222 addresource(h
, FOUR_CHAR_CODE('Int '), id
, key
);
223 if (ResError() != noErr
)
224 fatalbox("Failed to add resource %s (%d)", key
, ResError());
227 void close_settings_w(void *handle
) {
228 struct write_settings
*ws
= handle
;
231 CloseResFile(ws
->fd
);
232 if ((error
= ResError()) != noErr
)
234 error
= FSpExchangeFiles(&ws
->tmpfile
, &ws
->dstfile
);
235 if (error
!= noErr
) goto out
;
236 error
= FSpDelete(&ws
->tmpfile
);
237 if (error
!= noErr
) goto out
;
241 fatalbox("Close of saved session failed (%d)", error
);
245 void *open_settings_r(char const *sessionname
)
253 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
255 c2pstrcpy(psessionname
, sessionname
);
256 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
257 if (error
!= noErr
) goto out
;
258 return open_settings_r_fsp(&sessfile
);
264 void *open_settings_r_fsp(FSSpec
*sessfile
)
270 fd
= FSpOpenResFile(sessfile
, fsRdPerm
);
271 if (fd
== 0) {error
= ResError(); goto out
;}
273 handle
= safemalloc(sizeof *handle
);
281 char *read_setting_s(void *handle
, char const *key
, char *buffer
, int buflen
) {
286 if (handle
== NULL
) goto out
;
289 if (ResError() != noErr
) goto out
;
290 h
= get1namedresource(FOUR_CHAR_CODE('TEXT'), key
);
291 if (h
== NULL
) goto out
;
293 len
= GetHandleSize(h
);
294 if (len
+ 1 > buflen
) goto out
;
295 memcpy(buffer
, *h
, len
);
299 if (ResError() != noErr
) goto out
;
306 int read_setting_i(void *handle
, char const *key
, int defvalue
) {
311 if (handle
== NULL
) goto out
;
314 if (ResError() != noErr
) goto out
;
315 h
= get1namedresource(FOUR_CHAR_CODE('Int '), key
);
316 if (h
== NULL
) goto out
;
319 if (ResError() != noErr
) goto out
;
326 int read_setting_fontspec(void *handle
, const char *name
, FontSpec
*result
)
332 if (!read_setting_s(handle
, name
, tmp
, sizeof(tmp
)))
334 c2pstrcpy(ret
.name
, tmp
);
335 settingname
= dupcat(name
, "Face", NULL
);
336 ret
.face
= read_setting_i(handle
, settingname
, 0);
338 settingname
= dupcat(name
, "Height", NULL
);
339 ret
.size
= read_setting_i(handle
, settingname
, 0);
341 if (ret
.size
== 0) return 0;
346 void write_setting_fontspec(void *handle
, const char *name
, FontSpec font
)
351 p2cstrcpy(tmp
, font
.name
);
352 write_setting_s(handle
, name
, tmp
);
353 settingname
= dupcat(name
, "Face", NULL
);
354 write_setting_i(handle
, settingname
, font
.face
);
356 settingname
= dupcat(name
, "Size", NULL
);
357 write_setting_i(handle
, settingname
, font
.size
);
361 int read_setting_filename(void *handle
, const char *name
, Filename
*result
)
368 if (handle
== NULL
) goto out
;
371 if (ResError() != noErr
) goto out
;
372 h
= (AliasHandle
)get1namedresource(rAliasType
, name
);
373 if (h
== NULL
) goto out
;
374 if ((*h
)->userType
== 'pTTY' && (*h
)->aliasSize
== sizeof(**h
))
375 memset(result
, 0, sizeof(*result
));
377 err
= ResolveAlias(NULL
, h
, &result
->fss
, &changed
);
378 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
379 if ((*h
)->userType
== 'pTTY') {
383 /* Tail of record is pascal string contaning leafname */
384 if (FSpGetDirID(&result
->fss
, &dirid
, FALSE
) != noErr
) goto out
;
385 memcpy(fname
, (char *)*h
+ (*h
)->aliasSize
,
386 GetHandleSize((Handle
)h
) - (*h
)->aliasSize
);
387 err
= FSMakeFSSpec(result
->fss
.vRefNum
, dirid
, fname
,
389 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
392 ReleaseResource((Handle
)h
);
393 if (ResError() != noErr
) goto out
;
400 void write_setting_filename(void *handle
, const char *name
, Filename fn
)
402 int fd
= *(int *)handle
;
408 if (ResError() != noErr
)
409 fatalbox("Failed to open saved session (%d)", ResError());
411 if (filename_is_null(fn
)) {
412 /* Generate a special "null" alias */
413 h
= (AliasHandle
)NewHandle(sizeof(**h
));
415 fatalbox("Failed to create fake alias");
416 (*h
)->userType
= 'pTTY';
417 (*h
)->aliasSize
= sizeof(**h
);
419 error
= NewAlias(NULL
, &fn
.fss
, &h
);
420 if (error
== fnfErr
) {
422 * NewAlias can't create an alias for a nonexistent file.
423 * Create an alias for the directory, and record the
428 FSMakeFSSpec(fn
.fss
.vRefNum
, fn
.fss
.parID
, NULL
, &tmpfss
);
429 error
= NewAlias(NULL
, &tmpfss
, &h
);
431 fatalbox("Failed to create alias");
432 (*h
)->userType
= 'pTTY';
433 SetHandleSize((Handle
)h
, (*h
)->aliasSize
+ fn
.fss
.name
[0] + 1);
434 if (MemError() != noErr
)
435 fatalbox("Failed to create alias");
436 memcpy((char *)*h
+ (*h
)->aliasSize
, fn
.fss
.name
,
440 fatalbox("Failed to create alias");
442 /* Put the data in a resource. */
443 id
= Unique1ID(rAliasType
);
444 if (ResError() != noErr
)
445 fatalbox("Failed to get ID for resource %s (%d)", name
, ResError());
446 addresource((Handle
)h
, rAliasType
, id
, name
);
447 if (ResError() != noErr
)
448 fatalbox("Failed to add resource %s (%d)", name
, ResError());
451 void close_settings_r(void *handle
) {
454 if (handle
== NULL
) return;
457 if (ResError() != noErr
)
458 fatalbox("Close of saved session failed (%d)", ResError());
462 void del_settings(char const *sessionname
) {
469 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
471 c2pstrcpy(psessionname
, sessionname
);
472 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
473 if (error
!= noErr
) goto out
;
475 error
= FSpDelete(&sessfile
);
478 fatalbox("Delete session failed (%d)", error
);
481 struct enum_settings_state
{
487 void *enum_settings_start(void) {
489 struct enum_settings_state
*state
;
491 state
= safemalloc(sizeof(*state
));
492 error
= get_session_dir(kDontCreateFolder
, &state
->vRefNum
, &state
->dirID
);
493 if (error
!= noErr
) {
501 char *enum_settings_next(void *handle
, char *buffer
, int buflen
) {
502 struct enum_settings_state
*e
= handle
;
507 if (e
== NULL
) return NULL
;
509 pb
.hFileInfo
.ioNamePtr
= name
;
510 pb
.hFileInfo
.ioVRefNum
= e
->vRefNum
;
511 pb
.hFileInfo
.ioDirID
= e
->dirID
;
512 pb
.hFileInfo
.ioFDirIndex
= e
->index
++;
513 error
= PBGetCatInfoSync(&pb
);
514 if (error
!= noErr
) return NULL
;
515 } while (!((pb
.hFileInfo
.ioFlAttrib
& ioDirMask
) == 0 &&
516 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
== PUTTY_CREATOR
&&
517 pb
.hFileInfo
.ioFlFndrInfo
.fdType
== SESS_TYPE
&&
520 p2cstrcpy(buffer
, name
);
524 void enum_settings_finish(void *handle
) {
529 #define SEED_SIZE 512
531 void read_random_seed(noise_consumer_t consumer
)
538 long count
= SEED_SIZE
;
540 if (get_putty_dir(kDontCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
542 if (HOpenDF(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed", fsRdPerm
,
545 error
= FSRead(refnum
, &count
, buf
);
546 if (error
!= noErr
&& error
!= eofErr
)
548 (*consumer
)(buf
, count
);
553 * We don't bother with the usual FSpExchangeFiles dance here because
554 * it doesn't really matter if the old random seed gets lost.
556 void write_random_seed(void *data
, int len
)
565 if (get_putty_dir(kCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
568 error
= FSMakeFSSpec(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed",
570 if (error
== fnfErr
) {
571 /* Set up standard resources */
572 FSpCreateResFile(&dstfile
, INTERNAL_CREATOR
, SEED_TYPE
, smRoman
);
573 refnum
= FSpOpenResFile(&dstfile
, fsWrPerm
);
574 if (ResError() == noErr
) {
575 copy_resource('STR ', -16397);
576 CloseResFile(refnum
);
578 } else if (error
!= noErr
) return;
580 if (FSpOpenDF(&dstfile
, fsWrPerm
, &refnum
) != noErr
) return;
581 FSWrite(refnum
, &count
, data
);
590 * c-file-style: "simon"