1 /* $Id: macstore.c,v 1.16 2003/02/02 00:04:36 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
;
189 if (ResError() != noErr
)
190 fatalbox("Failed to open saved session (%d)", ResError());
192 error
= PtrToHand(value
, &h
, strlen(value
));
194 fatalbox("Failed to allocate memory");
195 /* Put the data in a resource. */
196 id
= Unique1ID(FOUR_CHAR_CODE('TEXT'));
197 if (ResError() != noErr
)
198 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
199 c2pstrcpy(pkey
, key
);
200 AddResource(h
, FOUR_CHAR_CODE('TEXT'), id
, pkey
);
201 if (ResError() != noErr
)
202 fatalbox("Failed to add resource %s (%d)", key
, ResError());
205 void write_setting_i(void *handle
, char const *key
, int value
) {
206 int fd
= *(int *)handle
;
213 if (ResError() != noErr
)
214 fatalbox("Failed to open saved session (%d)", ResError());
216 /* XXX assume all systems have the same "int" format */
217 error
= PtrToHand(&value
, &h
, sizeof(int));
219 fatalbox("Failed to allocate memory (%d)", error
);
221 /* Put the data in a resource. */
222 id
= Unique1ID(FOUR_CHAR_CODE('Int '));
223 if (ResError() != noErr
)
224 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
225 c2pstrcpy(pkey
, key
);
226 AddResource(h
, FOUR_CHAR_CODE('Int '), id
, pkey
);
227 if (ResError() != noErr
)
228 fatalbox("Failed to add resource %s (%d)", key
, ResError());
231 void close_settings_w(void *handle
) {
232 struct write_settings
*ws
= handle
;
235 CloseResFile(ws
->fd
);
236 if ((error
= ResError()) != noErr
)
238 error
= FSpExchangeFiles(&ws
->tmpfile
, &ws
->dstfile
);
239 if (error
!= noErr
) goto out
;
240 error
= FSpDelete(&ws
->tmpfile
);
241 if (error
!= noErr
) goto out
;
245 fatalbox("Close of saved session failed (%d)", error
);
249 void *open_settings_r(char const *sessionname
)
257 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
259 c2pstrcpy(psessionname
, sessionname
);
260 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
261 if (error
!= noErr
) goto out
;
262 return open_settings_r_fsp(&sessfile
);
268 void *open_settings_r_fsp(FSSpec
*sessfile
)
274 fd
= FSpOpenResFile(sessfile
, fsRdPerm
);
275 if (fd
== 0) {error
= ResError(); goto out
;}
277 handle
= smalloc(sizeof *handle
);
285 char *read_setting_s(void *handle
, char const *key
, char *buffer
, int buflen
) {
291 if (handle
== NULL
) goto out
;
294 if (ResError() != noErr
) goto out
;
295 c2pstrcpy(pkey
, key
);
296 h
= Get1NamedResource(FOUR_CHAR_CODE('TEXT'), pkey
);
297 if (h
== NULL
) goto out
;
299 len
= GetHandleSize(h
);
300 if (len
+ 1 > buflen
) goto out
;
301 memcpy(buffer
, *h
, len
);
305 if (ResError() != noErr
) goto out
;
312 int read_setting_i(void *handle
, char const *key
, int defvalue
) {
318 if (handle
== NULL
) goto out
;
321 if (ResError() != noErr
) goto out
;
322 c2pstrcpy(pkey
, key
);
323 h
= Get1NamedResource(FOUR_CHAR_CODE('Int '), pkey
);
324 if (h
== NULL
) goto out
;
327 if (ResError() != noErr
) goto out
;
334 int read_setting_fontspec(void *handle
, const char *name
, FontSpec
*result
)
340 if (!read_setting_s(handle
, name
, tmp
, sizeof(tmp
)))
342 c2pstrcpy(ret
.name
, tmp
);
343 settingname
= dupcat(name
, "Face", NULL
);
344 ret
.face
= read_setting_i(handle
, settingname
, 0);
346 settingname
= dupcat(name
, "Height", NULL
);
347 ret
.size
= read_setting_i(handle
, settingname
, 0);
349 if (ret
.size
== 0) return 0;
354 void write_setting_fontspec(void *handle
, const char *name
, FontSpec font
)
359 p2cstrcpy(tmp
, font
.name
);
360 write_setting_s(handle
, name
, tmp
);
361 settingname
= dupcat(name
, "Face", NULL
);
362 write_setting_i(handle
, settingname
, font
.face
);
364 settingname
= dupcat(name
, "Size", NULL
);
365 write_setting_i(handle
, settingname
, font
.size
);
369 int read_setting_filename(void *handle
, const char *key
, Filename
*result
)
377 if (handle
== NULL
) goto out
;
380 if (ResError() != noErr
) goto out
;
381 c2pstrcpy(pkey
, key
);
382 h
= (AliasHandle
)Get1NamedResource(rAliasType
, pkey
);
383 if (h
== NULL
) goto out
;
384 if ((*h
)->userType
== 'pTTY' && (*h
)->aliasSize
== sizeof(**h
))
385 memset(result
, 0, sizeof(*result
));
387 err
= ResolveAlias(NULL
, h
, &result
->fss
, &changed
);
388 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
389 if ((*h
)->userType
== 'pTTY') {
393 /* Tail of record is pascal string contaning leafname */
394 if (FSpGetDirID(&result
->fss
, &dirid
, FALSE
) != noErr
) goto out
;
395 memcpy(fname
, (char *)*h
+ (*h
)->aliasSize
,
396 GetHandleSize((Handle
)h
) - (*h
)->aliasSize
);
397 err
= FSMakeFSSpec(result
->fss
.vRefNum
, dirid
, fname
,
399 if (err
!= noErr
&& err
!= fnfErr
) goto out
;
402 ReleaseResource((Handle
)h
);
403 if (ResError() != noErr
) goto out
;
410 void write_setting_filename(void *handle
, const char *key
, Filename fn
)
412 int fd
= *(int *)handle
;
419 if (ResError() != noErr
)
420 fatalbox("Failed to open saved session (%d)", ResError());
422 if (filename_is_null(fn
)) {
423 /* Generate a special "null" alias */
424 h
= (AliasHandle
)NewHandle(sizeof(**h
));
426 fatalbox("Failed to create fake alias");
427 (*h
)->userType
= 'pTTY';
428 (*h
)->aliasSize
= sizeof(**h
);
430 error
= NewAlias(NULL
, &fn
.fss
, &h
);
431 if (error
== fnfErr
) {
433 * NewAlias can't create an alias for a nonexistent file.
434 * Create an alias for the directory, and record the
439 FSMakeFSSpec(fn
.fss
.vRefNum
, fn
.fss
.parID
, NULL
, &tmpfss
);
440 error
= NewAlias(NULL
, &tmpfss
, &h
);
442 fatalbox("Failed to create alias");
443 (*h
)->userType
= 'pTTY';
444 SetHandleSize((Handle
)h
, (*h
)->aliasSize
+ fn
.fss
.name
[0] + 1);
445 if (MemError() != noErr
)
446 fatalbox("Failed to create alias");
447 memcpy((char *)*h
+ (*h
)->aliasSize
, fn
.fss
.name
,
451 fatalbox("Failed to create alias");
453 /* Put the data in a resource. */
454 id
= Unique1ID(rAliasType
);
455 if (ResError() != noErr
)
456 fatalbox("Failed to get ID for resource %s (%d)", key
, ResError());
457 c2pstrcpy(pkey
, key
);
458 AddResource((Handle
)h
, rAliasType
, id
, pkey
);
459 if (ResError() != noErr
)
460 fatalbox("Failed to add resource %s (%d)", key
, ResError());
463 void close_settings_r(void *handle
) {
466 if (handle
== NULL
) return;
469 if (ResError() != noErr
)
470 fatalbox("Close of saved session failed (%d)", ResError());
474 void del_settings(char const *sessionname
) {
481 error
= get_session_dir(kDontCreateFolder
, &sessVRefNum
, &sessDirID
);
483 c2pstrcpy(psessionname
, sessionname
);
484 error
= FSMakeFSSpec(sessVRefNum
, sessDirID
, psessionname
, &sessfile
);
485 if (error
!= noErr
) goto out
;
487 error
= FSpDelete(&sessfile
);
490 fatalbox("Delete session failed (%d)", error
);
493 struct enum_settings_state
{
499 void *enum_settings_start(void) {
501 struct enum_settings_state
*state
;
503 state
= safemalloc(sizeof(*state
));
504 error
= get_session_dir(kDontCreateFolder
, &state
->vRefNum
, &state
->dirID
);
505 if (error
!= noErr
) {
513 char *enum_settings_next(void *handle
, char *buffer
, int buflen
) {
514 struct enum_settings_state
*e
= handle
;
519 if (e
== NULL
) return NULL
;
521 pb
.hFileInfo
.ioNamePtr
= name
;
522 pb
.hFileInfo
.ioVRefNum
= e
->vRefNum
;
523 pb
.hFileInfo
.ioDirID
= e
->dirID
;
524 pb
.hFileInfo
.ioFDirIndex
= e
->index
++;
525 error
= PBGetCatInfoSync(&pb
);
526 if (error
!= noErr
) return NULL
;
527 } while (!((pb
.hFileInfo
.ioFlAttrib
& ioDirMask
) == 0 &&
528 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
== PUTTY_CREATOR
&&
529 pb
.hFileInfo
.ioFlFndrInfo
.fdType
== SESS_TYPE
&&
532 p2cstrcpy(buffer
, name
);
536 void enum_settings_finish(void *handle
) {
541 #define SEED_SIZE 512
543 void read_random_seed(noise_consumer_t consumer
)
550 long count
= SEED_SIZE
;
552 if (get_putty_dir(kDontCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
554 if (HOpenDF(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed", fsRdPerm
,
557 error
= FSRead(refnum
, &count
, buf
);
558 if (error
!= noErr
&& error
!= eofErr
)
560 (*consumer
)(buf
, count
);
565 * We don't bother with the usual FSpExchangeFiles dance here because
566 * it doesn't really matter if the old random seed gets lost.
568 void write_random_seed(void *data
, int len
)
577 if (get_putty_dir(kCreateFolder
, &puttyVRefNum
, &puttyDirID
) != noErr
)
580 error
= FSMakeFSSpec(puttyVRefNum
, puttyDirID
, "\pPuTTY Random Seed",
582 if (error
== fnfErr
) {
583 /* Set up standard resources */
584 FSpCreateResFile(&dstfile
, INTERNAL_CREATOR
, SEED_TYPE
, smRoman
);
585 refnum
= FSpOpenResFile(&dstfile
, fsWrPerm
);
586 if (ResError() == noErr
) {
587 copy_resource('STR ', -16397);
588 CloseResFile(refnum
);
590 } else if (error
!= noErr
) return;
592 if (FSpOpenDF(&dstfile
, fsWrPerm
, &refnum
) != noErr
) return;
593 FSWrite(refnum
, &count
, data
);
602 * c-file-style: "simon"