]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
66e82014e33d41155cc6d14357cfed1d077e3df1
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.10 2003/01/18 16:10:21 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 <string.h>
15
16 #include "putty.h"
17 #include "storage.h"
18 #include "mac.h"
19 #include "macresid.h"
20
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')
25
26
27 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
28
29 /*
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.
32  */
33
34 OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
35 {
36     OSErr error = noErr;
37     short prefVRefNum;
38     FSSpec puttydir;
39     long prefDirID, puttyDirID;
40
41     error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
42                        &prefVRefNum, &prefDirID);
43     if (error != noErr) goto out;
44
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;
49
50     *pVRefNum = prefVRefNum;
51     *pDirID = puttyDirID;
52
53   out:
54     return error;
55 }
56
57 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
58     OSErr error = noErr;
59     short puttyVRefNum;
60     FSSpec sessdir;
61     long puttyDirID, sessDirID;
62
63     error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
64     if (error != noErr) goto out;
65     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
66                          &sessdir);
67     if (error != noErr && error != fnfErr) goto out;
68     error = FSpGetDirID(&sessdir, &sessDirID, makeit);
69     if (error != noErr) goto out;
70
71     *pVRefNum = puttyVRefNum;
72     *pDirID = sessDirID;
73
74   out:
75     return error;
76 }
77
78 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
79     CInfoPBRec pb;
80     OSErr error = noErr;
81
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) {
91         error = dirNFErr;
92         goto out;
93     }
94     *idp = pb.dirInfo.ioDrDirID;
95
96   out:
97     return error;
98 }
99
100 /* Copy a resource into the current resource file */
101 static OSErr copy_resource(ResType restype, short resid)
102 {
103     Handle h;
104     Str255 resname;
105
106     fprintf(stderr, "getting resource %x, id %d\n", restype, resid);
107     h = GetResource(restype, resid);
108     if (h != NULL) {
109         GetResInfo(h, &resid, &restype, resname);
110         DetachResource(h);
111         AddResource(h, restype, resid, resname);
112         if (ResError() == noErr)
113             WriteResource(h);
114     }
115     fprintf(stderr, "ResError() == %d\n", ResError());
116     return ResError();
117 }
118
119 struct write_settings {
120     int fd;
121     FSSpec tmpfile;
122     FSSpec dstfile;
123 };
124
125 void *open_settings_w(char const *sessionname) {
126     short sessVRefNum, tmpVRefNum;
127     long sessDirID, tmpDirID;
128     OSErr error;
129     Str255 psessionname;
130     struct write_settings *ws;
131     
132     ws = safemalloc(sizeof *ws);
133     error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
134     if (error != noErr) goto out;
135
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,
141                          smSystemScript);
142         if ((error = ResError()) != noErr) goto out;
143     }
144
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;
154     }
155     FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
156     if ((error = ResError()) != noErr) goto out;
157
158     ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
159     if (ws->fd == -1) {error = ResError(); goto out;}
160
161     /* Set up standard resources.  Doesn't matter if these fail. */
162     copy_resource('STR ', -16396);
163     copy_resource('TMPL', TMPL_Int);
164
165     return ws;
166
167   out:
168     safefree(ws);
169     fatalbox("Failed to open session for write (%d)", error);
170 }
171
172 void write_setting_s(void *handle, char const *key, char const *value) {
173     int fd = *(int *)handle;
174     Handle h;
175     int id;
176     OSErr error;
177
178     UseResFile(fd);
179     if (ResError() != noErr)
180         fatalbox("Failed to open saved session (%d)", ResError());
181
182     error = PtrToHand(value, &h, strlen(value));
183     if (error != noErr)
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());
192 }
193
194 void write_setting_i(void *handle, char const *key, int value) {
195     int fd = *(int *)handle;
196     Handle h;
197     int id;
198     OSErr error;
199
200     UseResFile(fd);
201     if (ResError() != noErr)
202         fatalbox("Failed to open saved session (%d)", ResError());
203
204     /* XXX assume all systems have the same "int" format */
205     error = PtrToHand(&value, &h, sizeof(int));
206     if (error != noErr)
207         fatalbox("Failed to allocate memory (%d)", error);
208
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());
216 }
217
218 void close_settings_w(void *handle) {
219     struct write_settings *ws = handle;
220     OSErr error;
221
222     CloseResFile(ws->fd);
223     if ((error = ResError()) != noErr)
224         goto out;
225     error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
226     if (error != noErr) goto out;
227     error = FSpDelete(&ws->tmpfile);
228     if (error != noErr) goto out;
229     return;
230
231   out:
232     fatalbox("Close of saved session failed (%d)", error);
233     safefree(handle);
234 }
235
236 void *open_settings_r(char const *sessionname)
237 {
238     short sessVRefNum;
239     long sessDirID;
240     FSSpec sessfile;
241     OSErr error;
242     Str255 psessionname;
243
244     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
245
246     c2pstrcpy(psessionname, sessionname);
247     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
248     if (error != noErr) goto out;
249     return open_settings_r_fsp(&sessfile);
250
251   out:
252     return NULL;
253 }
254
255 void *open_settings_r_fsp(FSSpec *sessfile)
256 {
257     OSErr error;
258     int fd;
259     int *handle;
260
261     fd = FSpOpenResFile(sessfile, fsRdPerm);
262     if (fd == 0) {error = ResError(); goto out;}
263
264     handle = safemalloc(sizeof *handle);
265     *handle = fd;
266     return handle;
267
268   out:
269     return NULL;
270 }
271
272 char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
273     int fd;
274     Handle h;
275     size_t len;
276
277     if (handle == NULL) goto out;
278     fd = *(int *)handle;
279     UseResFile(fd);
280     if (ResError() != noErr) goto out;
281     h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
282     if (h == NULL) goto out;
283
284     len = GetHandleSize(h);
285     if (len + 1 > buflen) goto out;
286     memcpy(buffer, *h, len);
287     buffer[len] = '\0';
288
289     ReleaseResource(h);
290     if (ResError() != noErr) goto out;
291     return buffer;
292
293   out:
294     return NULL;
295 }
296
297 int read_setting_i(void *handle, char const *key, int defvalue) {
298     int fd;
299     Handle h;
300     int value;
301
302     if (handle == NULL) goto out;
303     fd = *(int *)handle;
304     UseResFile(fd);
305     if (ResError() != noErr) goto out;
306     h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
307     if (h == NULL) goto out;
308     value = *(int *)*h;
309     ReleaseResource(h);
310     if (ResError() != noErr) goto out;
311     return value;
312
313   out:
314     return defvalue;
315 }
316
317 void close_settings_r(void *handle) {
318     int fd;
319
320     if (handle == NULL) return;
321     fd = *(int *)handle;
322     CloseResFile(fd);
323     if (ResError() != noErr)
324         fatalbox("Close of saved session failed (%d)", ResError());
325     safefree(handle);
326 }
327
328 void del_settings(char const *sessionname) {
329     OSErr error;
330     FSSpec sessfile;
331     short sessVRefNum;
332     long sessDirID;
333     Str255 psessionname;
334
335     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
336
337     c2pstrcpy(psessionname, sessionname);
338     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
339     if (error != noErr) goto out;
340
341     error = FSpDelete(&sessfile);
342     return;
343   out:
344     fatalbox("Delete session failed (%d)", error);
345 }
346
347 struct enum_settings_state {
348     short vRefNum;
349     long dirID;
350     int index;
351 };
352
353 void *enum_settings_start(void) {
354     OSErr error;
355     struct enum_settings_state *state;
356
357     state = safemalloc(sizeof(*state));
358     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
359     if (error != noErr) {
360         safefree(state);
361         return NULL;
362     }
363     state->index = 1;
364     return state;
365 }
366
367 char *enum_settings_next(void *handle, char *buffer, int buflen) {
368     struct enum_settings_state *e = handle;
369     CInfoPBRec pb;
370     OSErr error = noErr;
371     Str255 name;
372
373     if (e == NULL) return NULL;
374     do {
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 &&
384                name[0] < buflen));
385
386     p2cstrcpy(buffer, name);
387     return buffer;
388 }
389
390 void enum_settings_finish(void *handle) {
391
392     safefree(handle);
393 }
394
395 #define SEED_SIZE 512
396
397 void read_random_seed(noise_consumer_t consumer)
398 {
399     short puttyVRefNum;
400     long puttyDirID;
401     OSErr error;
402     char buf[SEED_SIZE];
403     short refnum;
404     long count = SEED_SIZE;
405
406     if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
407         return;
408     if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
409                 &refnum) != noErr)
410         return;
411     error = FSRead(refnum, &count, buf);
412     if (error != noErr && error != eofErr)
413         return;
414     (*consumer)(buf, count);
415     FSClose(refnum);
416 }
417
418 /*
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.
421  */
422 void write_random_seed(void *data, int len)
423 {
424     short puttyVRefNum;
425     long puttyDirID;
426     OSErr error;
427     FSSpec dstfile;
428     short refnum;
429     long count = len;
430
431     if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
432         return;
433
434     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
435                          &dstfile);
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);
443         }
444     } else if (error != noErr) return;
445
446     if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
447     FSWrite(refnum, &count, data);
448     FSClose(refnum);
449
450     return;
451 }
452
453 /*
454  * Emacs magic:
455  * Local Variables:
456  * c-file-style: "simon"
457  * End:
458  */