]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
Stub code for handling key windows in PuTTYgen. This file will eventually
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.16 2003/02/02 00:04:36 ben Exp $ */
2
3 /*
4  * macstore.c: Macintosh-specific impementation of the interface
5  * defined in storage.h
6  */
7
8 #include <MacTypes.h>
9 #include <Folders.h>
10 #include <Memory.h>
11 #include <Resources.h>
12 #include <TextUtils.h>
13
14 #include <stdio.h>
15 #include <string.h>
16
17 #include "putty.h"
18 #include "storage.h"
19 #include "mac.h"
20 #include "macresid.h"
21
22
23 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
24
25 /*
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.
28  */
29
30 OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
31 {
32     OSErr error = noErr;
33     short prefVRefNum;
34     FSSpec puttydir;
35     long prefDirID, puttyDirID;
36
37     error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
38                        &prefVRefNum, &prefDirID);
39     if (error != noErr) goto out;
40
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;
45
46     *pVRefNum = prefVRefNum;
47     *pDirID = puttyDirID;
48
49   out:
50     return error;
51 }
52
53 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
54     OSErr error = noErr;
55     short puttyVRefNum;
56     FSSpec sessdir;
57     long puttyDirID, sessDirID;
58
59     error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
60     if (error != noErr) goto out;
61     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
62                          &sessdir);
63     if (error != noErr && error != fnfErr) goto out;
64     error = FSpGetDirID(&sessdir, &sessDirID, makeit);
65     if (error != noErr) goto out;
66
67     *pVRefNum = puttyVRefNum;
68     *pDirID = sessDirID;
69
70   out:
71     return error;
72 }
73
74 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
75     CInfoPBRec pb;
76     OSErr error = noErr;
77
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) {
87         error = dirNFErr;
88         goto out;
89     }
90     *idp = pb.dirInfo.ioDrDirID;
91
92   out:
93     return error;
94 }
95
96 /* Copy a resource into the current resource file */
97 static OSErr copy_resource(ResType restype, short resid)
98 {
99     Handle h;
100     Str255 resname;
101
102     h = GetResource(restype, resid);
103     if (h != NULL) {
104         GetResInfo(h, &resid, &restype, resname);
105         DetachResource(h);
106         AddResource(h, restype, resid, resname);
107         if (ResError() == noErr)
108             WriteResource(h);
109     }
110     return ResError();
111 }
112
113 struct write_settings {
114     int fd;
115     FSSpec tmpfile;
116     FSSpec dstfile;
117 };
118
119 void *open_settings_w(char const *sessionname) {
120     short sessVRefNum;
121     long sessDirID;
122     OSErr error;
123     Str255 psessionname;
124     FSSpec dstfile;
125     
126     error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
127     if (error != noErr) return NULL;
128
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;
135
136     return open_settings_w_fsp(&dstfile);
137 }
138
139 /*
140  * NB: Destination file must exist.
141  */
142 void *open_settings_w_fsp(FSSpec *dstfile)
143 {
144     short tmpVRefNum;
145     long tmpDirID;
146     struct write_settings *ws;
147     OSErr error;
148     Str255 tmpname;
149
150     ws = smalloc(sizeof *ws);
151     ws->dstfile = *dstfile;
152
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;
163     }
164     FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
165     if ((error = ResError()) != noErr) goto out;
166
167     ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
168     if (ws->fd == -1) {error = ResError(); goto out;}
169
170     /* Set up standard resources.  Doesn't matter if these fail. */
171     copy_resource('STR ', -16396);
172     copy_resource('TMPL', TMPL_Int);
173
174     return ws;
175
176   out:
177     safefree(ws);
178     fatalbox("Failed to open session for write (%d)", error);
179 }
180
181 void write_setting_s(void *handle, char const *key, char const *value) {
182     int fd = *(int *)handle;
183     Handle h;
184     int id;
185     OSErr error;
186     Str255 pkey;
187
188     UseResFile(fd);
189     if (ResError() != noErr)
190         fatalbox("Failed to open saved session (%d)", ResError());
191
192     error = PtrToHand(value, &h, strlen(value));
193     if (error != noErr)
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());
203 }
204
205 void write_setting_i(void *handle, char const *key, int value) {
206     int fd = *(int *)handle;
207     Handle h;
208     int id;
209     OSErr error;
210     Str255 pkey;
211
212     UseResFile(fd);
213     if (ResError() != noErr)
214         fatalbox("Failed to open saved session (%d)", ResError());
215
216     /* XXX assume all systems have the same "int" format */
217     error = PtrToHand(&value, &h, sizeof(int));
218     if (error != noErr)
219         fatalbox("Failed to allocate memory (%d)", error);
220
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());
229 }
230
231 void close_settings_w(void *handle) {
232     struct write_settings *ws = handle;
233     OSErr error;
234
235     CloseResFile(ws->fd);
236     if ((error = ResError()) != noErr)
237         goto out;
238     error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
239     if (error != noErr) goto out;
240     error = FSpDelete(&ws->tmpfile);
241     if (error != noErr) goto out;
242     return;
243
244   out:
245     fatalbox("Close of saved session failed (%d)", error);
246     safefree(handle);
247 }
248
249 void *open_settings_r(char const *sessionname)
250 {
251     short sessVRefNum;
252     long sessDirID;
253     FSSpec sessfile;
254     OSErr error;
255     Str255 psessionname;
256
257     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
258
259     c2pstrcpy(psessionname, sessionname);
260     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
261     if (error != noErr) goto out;
262     return open_settings_r_fsp(&sessfile);
263
264   out:
265     return NULL;
266 }
267
268 void *open_settings_r_fsp(FSSpec *sessfile)
269 {
270     OSErr error;
271     int fd;
272     int *handle;
273
274     fd = FSpOpenResFile(sessfile, fsRdPerm);
275     if (fd == 0) {error = ResError(); goto out;}
276
277     handle = smalloc(sizeof *handle);
278     *handle = fd;
279     return handle;
280
281   out:
282     return NULL;
283 }
284
285 char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
286     int fd;
287     Handle h;
288     size_t len;
289     Str255 pkey;
290
291     if (handle == NULL) goto out;
292     fd = *(int *)handle;
293     UseResFile(fd);
294     if (ResError() != noErr) goto out;
295     c2pstrcpy(pkey, key);
296     h = Get1NamedResource(FOUR_CHAR_CODE('TEXT'), pkey);
297     if (h == NULL) goto out;
298
299     len = GetHandleSize(h);
300     if (len + 1 > buflen) goto out;
301     memcpy(buffer, *h, len);
302     buffer[len] = '\0';
303
304     ReleaseResource(h);
305     if (ResError() != noErr) goto out;
306     return buffer;
307
308   out:
309     return NULL;
310 }
311
312 int read_setting_i(void *handle, char const *key, int defvalue) {
313     int fd;
314     Handle h;
315     int value;
316     Str255 pkey;
317
318     if (handle == NULL) goto out;
319     fd = *(int *)handle;
320     UseResFile(fd);
321     if (ResError() != noErr) goto out;
322     c2pstrcpy(pkey, key);
323     h = Get1NamedResource(FOUR_CHAR_CODE('Int '), pkey);
324     if (h == NULL) goto out;
325     value = *(int *)*h;
326     ReleaseResource(h);
327     if (ResError() != noErr) goto out;
328     return value;
329
330   out:
331     return defvalue;
332 }
333
334 int read_setting_fontspec(void *handle, const char *name, FontSpec *result)
335 {
336     char *settingname;
337     FontSpec ret;
338     char tmp[256];
339
340     if (!read_setting_s(handle, name, tmp, sizeof(tmp)))
341         return 0;
342     c2pstrcpy(ret.name, tmp);
343     settingname = dupcat(name, "Face", NULL);
344     ret.face = read_setting_i(handle, settingname, 0);
345     sfree(settingname);
346     settingname = dupcat(name, "Height", NULL);
347     ret.size = read_setting_i(handle, settingname, 0);
348     sfree(settingname);
349     if (ret.size == 0) return 0;
350     *result = ret;
351     return 1;
352 }
353
354 void write_setting_fontspec(void *handle, const char *name, FontSpec font)
355 {
356     char *settingname;
357     char tmp[256];
358
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);
363     sfree(settingname);
364     settingname = dupcat(name, "Size", NULL);
365     write_setting_i(handle, settingname, font.size);
366     sfree(settingname);
367 }
368
369 int read_setting_filename(void *handle, const char *key, Filename *result)
370 {
371     int fd;
372     AliasHandle h;
373     Boolean changed;
374     OSErr err;
375     Str255 pkey;
376
377     if (handle == NULL) goto out;
378     fd = *(int *)handle;
379     UseResFile(fd);
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));
386     else {
387         err = ResolveAlias(NULL, h, &result->fss, &changed);
388         if (err != noErr && err != fnfErr) goto out;
389         if ((*h)->userType == 'pTTY') {
390             long dirid;
391             StrFileName fname;
392
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,
398                                &result->fss);
399             if (err != noErr && err != fnfErr) goto out;
400         }
401     }
402     ReleaseResource((Handle)h);
403     if (ResError() != noErr) goto out;
404     return 1;
405
406   out:
407     return 0;
408 }
409
410 void write_setting_filename(void *handle, const char *key, Filename fn)
411 {
412     int fd = *(int *)handle;
413     AliasHandle h;
414     int id;
415     OSErr error;
416     Str255 pkey;
417
418     UseResFile(fd);
419     if (ResError() != noErr)
420         fatalbox("Failed to open saved session (%d)", ResError());
421
422     if (filename_is_null(fn)) {
423         /* Generate a special "null" alias */
424         h = (AliasHandle)NewHandle(sizeof(**h));
425         if (h == NULL)
426             fatalbox("Failed to create fake alias");
427         (*h)->userType = 'pTTY';
428         (*h)->aliasSize = sizeof(**h);
429     } else {
430         error = NewAlias(NULL, &fn.fss, &h);
431         if (error == fnfErr) {
432             /*
433              * NewAlias can't create an alias for a nonexistent file.
434              * Create an alias for the directory, and record the
435              * filename as well.
436              */
437             FSSpec tmpfss;
438
439             FSMakeFSSpec(fn.fss.vRefNum, fn.fss.parID, NULL, &tmpfss);
440             error = NewAlias(NULL, &tmpfss, &h);
441             if (error != noErr)
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,
448                    fn.fss.name[0] + 1);
449         }
450         if (error != noErr)
451             fatalbox("Failed to create alias");
452     }
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());
461 }
462
463 void close_settings_r(void *handle) {
464     int fd;
465
466     if (handle == NULL) return;
467     fd = *(int *)handle;
468     CloseResFile(fd);
469     if (ResError() != noErr)
470         fatalbox("Close of saved session failed (%d)", ResError());
471     sfree(handle);
472 }
473
474 void del_settings(char const *sessionname) {
475     OSErr error;
476     FSSpec sessfile;
477     short sessVRefNum;
478     long sessDirID;
479     Str255 psessionname;
480
481     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
482
483     c2pstrcpy(psessionname, sessionname);
484     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
485     if (error != noErr) goto out;
486
487     error = FSpDelete(&sessfile);
488     return;
489   out:
490     fatalbox("Delete session failed (%d)", error);
491 }
492
493 struct enum_settings_state {
494     short vRefNum;
495     long dirID;
496     int index;
497 };
498
499 void *enum_settings_start(void) {
500     OSErr error;
501     struct enum_settings_state *state;
502
503     state = safemalloc(sizeof(*state));
504     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
505     if (error != noErr) {
506         safefree(state);
507         return NULL;
508     }
509     state->index = 1;
510     return state;
511 }
512
513 char *enum_settings_next(void *handle, char *buffer, int buflen) {
514     struct enum_settings_state *e = handle;
515     CInfoPBRec pb;
516     OSErr error = noErr;
517     Str255 name;
518
519     if (e == NULL) return NULL;
520     do {
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 &&
530                name[0] < buflen));
531
532     p2cstrcpy(buffer, name);
533     return buffer;
534 }
535
536 void enum_settings_finish(void *handle) {
537
538     safefree(handle);
539 }
540
541 #define SEED_SIZE 512
542
543 void read_random_seed(noise_consumer_t consumer)
544 {
545     short puttyVRefNum;
546     long puttyDirID;
547     OSErr error;
548     char buf[SEED_SIZE];
549     short refnum;
550     long count = SEED_SIZE;
551
552     if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
553         return;
554     if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
555                 &refnum) != noErr)
556         return;
557     error = FSRead(refnum, &count, buf);
558     if (error != noErr && error != eofErr)
559         return;
560     (*consumer)(buf, count);
561     FSClose(refnum);
562 }
563
564 /*
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.
567  */
568 void write_random_seed(void *data, int len)
569 {
570     short puttyVRefNum;
571     long puttyDirID;
572     OSErr error;
573     FSSpec dstfile;
574     short refnum;
575     long count = len;
576
577     if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
578         return;
579
580     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
581                          &dstfile);
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);
589         }
590     } else if (error != noErr) return;
591
592     if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
593     FSWrite(refnum, &count, data);
594     FSClose(refnum);
595
596     return;
597 }
598
599 /*
600  * Emacs magic:
601  * Local Variables:
602  * c-file-style: "simon"
603  * End:
604  */