]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
Consequences of Simon's recent deglobalisation changes.
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.7 2003/01/08 22:46:12 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
20 #define PUTTY_CREATOR   FOUR_CHAR_CODE('pTTY')
21 #define SESS_TYPE       FOUR_CHAR_CODE('Sess')
22 #define SEED_TYPE       FOUR_CHAR_CODE('Seed')
23
24
25 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
26
27 /*
28  * We store each session as a file in the "PuTTY" sub-directory of the
29  * preferences folder.  Each (key,value) pair is stored as a resource.
30  */
31
32 OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
33 {
34     OSErr error = noErr;
35     short prefVRefNum;
36     FSSpec puttydir;
37     long prefDirID, puttyDirID;
38
39     error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
40                        &prefVRefNum, &prefDirID);
41     if (error != noErr) goto out;
42
43     error = FSMakeFSSpec(prefVRefNum, prefDirID, "\pPuTTY", &puttydir);
44     if (error != noErr && error != fnfErr) goto out;
45     error = FSpGetDirID(&puttydir, &puttyDirID, makeit);
46     if (error != noErr) goto out;
47
48     *pVRefNum = prefVRefNum;
49     *pDirID = puttyDirID;
50
51   out:
52     return error;
53 }
54
55 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
56     OSErr error = noErr;
57     short puttyVRefNum;
58     FSSpec sessdir;
59     long puttyDirID, sessDirID;
60
61     error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
62     if (error != noErr) goto out;
63     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
64                          &sessdir);
65     if (error != noErr && error != fnfErr) goto out;
66     error = FSpGetDirID(&sessdir, &sessDirID, makeit);
67     if (error != noErr) goto out;
68
69     *pVRefNum = puttyVRefNum;
70     *pDirID = sessDirID;
71
72   out:
73     return error;
74 }
75
76 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
77     CInfoPBRec pb;
78     OSErr error = noErr;
79
80     pb.dirInfo.ioNamePtr = f->name;
81     pb.dirInfo.ioVRefNum = f->vRefNum;
82     pb.dirInfo.ioDrDirID = f->parID;
83     pb.dirInfo.ioFDirIndex = 0;
84     error = PBGetCatInfoSync(&pb);
85     if (error == fnfErr && makeit)
86         return FSpDirCreate(f, smSystemScript, idp);
87     if (error != noErr) goto out;
88     if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
89         error = dirNFErr;
90         goto out;
91     }
92     *idp = pb.dirInfo.ioDrDirID;
93
94   out:
95     return error;
96 }
97
98 struct write_settings {
99     int fd;
100     FSSpec tmpfile;
101     FSSpec dstfile;
102 };
103
104 void *open_settings_w(char *sessionname) {
105     short sessVRefNum, tmpVRefNum;
106     long sessDirID, tmpDirID;
107     OSErr error;
108     Str255 psessionname;
109     struct write_settings *ws;
110     
111     ws = safemalloc(sizeof *ws);
112     error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
113     if (error != noErr) goto out;
114
115     c2pstrcpy(psessionname, sessionname);
116     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &ws->dstfile);
117     if (error != noErr && error != fnfErr) goto out;
118     if (error == fnfErr) {
119         FSpCreateResFile(&ws->dstfile, PUTTY_CREATOR, SESS_TYPE,
120                          smSystemScript);
121         if ((error = ResError()) != noErr) goto out;
122     }
123
124     /* Create a temporary file to save to first. */
125     error = FindFolder(sessVRefNum, kTemporaryFolderType, kCreateFolder,
126                        &tmpVRefNum, &tmpDirID);
127     if (error != noErr) goto out;
128     error = FSMakeFSSpec(tmpVRefNum, tmpDirID, psessionname, &ws->tmpfile);
129     if (error != noErr && error != fnfErr) goto out;
130     if (error == noErr) {
131         error = FSpDelete(&ws->tmpfile);
132         if (error != noErr) goto out;
133     }
134     FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
135     if ((error = ResError()) != noErr) goto out;
136
137     ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
138     if (ws->fd == -1) {error = ResError(); goto out;}
139
140     return ws;
141
142   out:
143     safefree(ws);
144     fatalbox("Failed to open session for write (%d)", error);
145 }
146
147 void write_setting_s(void *handle, char *key, char *value) {
148     int fd = *(int *)handle;
149     Handle h;
150     int id;
151     OSErr error;
152
153     UseResFile(fd);
154     if (ResError() != noErr)
155         fatalbox("Failed to open saved session (%d)", ResError());
156
157     error = PtrToHand(value, &h, strlen(value));
158     if (error != noErr)
159         fatalbox("Failed to allocate memory");
160     /* Put the data in a resource. */
161     id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
162     if (ResError() != noErr)
163         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
164     addresource(h, FOUR_CHAR_CODE('TEXT'), id, key);
165     if (ResError() != noErr)
166         fatalbox("Failed to add resource %s (%d)", key, ResError());
167 }
168
169 void write_setting_i(void *handle, char *key, int value) {
170     int fd = *(int *)handle;
171     Handle h;
172     int id;
173     OSErr error;
174
175     UseResFile(fd);
176     if (ResError() != noErr)
177         fatalbox("Failed to open saved session (%d)", ResError());
178
179     /* XXX assume all systems have the same "int" format */
180     error = PtrToHand(&value, &h, sizeof(int));
181     if (error != noErr)
182         fatalbox("Failed to allocate memory (%d)", error);
183
184     /* Put the data in a resource. */
185     id = Unique1ID(FOUR_CHAR_CODE('Int '));
186     if (ResError() != noErr)
187         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
188     addresource(h, FOUR_CHAR_CODE('Int '), id, key);
189     if (ResError() != noErr)
190         fatalbox("Failed to add resource %s (%d)", key, ResError());
191 }
192
193 void close_settings_w(void *handle) {
194     struct write_settings *ws = handle;
195     OSErr error;
196
197     CloseResFile(ws->fd);
198     if ((error = ResError()) != noErr)
199         goto out;
200     error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
201     if (error != noErr) goto out;
202     error = FSpDelete(&ws->tmpfile);
203     if (error != noErr) goto out;
204     return;
205
206   out:
207     fatalbox("Close of saved session failed (%d)", error);
208     safefree(handle);
209 }
210
211 void *open_settings_r(char *sessionname)
212 {
213     short sessVRefNum;
214     long sessDirID;
215     FSSpec sessfile;
216     OSErr error;
217     Str255 psessionname;
218
219     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
220
221     c2pstrcpy(psessionname, sessionname);
222     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
223     if (error != noErr) goto out;
224     return open_settings_r_fsp(&sessfile);
225
226   out:
227     return NULL;
228 }
229
230 void *open_settings_r_fsp(FSSpec *sessfile)
231 {
232     OSErr error;
233     int fd;
234     int *handle;
235
236     fd = FSpOpenResFile(sessfile, fsRdPerm);
237     if (fd == 0) {error = ResError(); goto out;}
238
239     handle = safemalloc(sizeof *handle);
240     *handle = fd;
241     return handle;
242
243   out:
244     return NULL;
245 }
246
247 char *read_setting_s(void *handle, char *key, char *buffer, int buflen) {
248     int fd;
249     Handle h;
250     size_t len;
251
252     if (handle == NULL) goto out;
253     fd = *(int *)handle;
254     UseResFile(fd);
255     if (ResError() != noErr) goto out;
256     h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
257     if (h == NULL) goto out;
258
259     len = GetHandleSize(h);
260     if (len + 1 > buflen) goto out;
261     memcpy(buffer, *h, len);
262     buffer[len] = '\0';
263
264     ReleaseResource(h);
265     if (ResError() != noErr) goto out;
266     return buffer;
267
268   out:
269     return NULL;
270 }
271
272 int read_setting_i(void *handle, char *key, int defvalue) {
273     int fd;
274     Handle h;
275     int value;
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('Int '), key);
282     if (h == NULL) goto out;
283     value = *(int *)*h;
284     ReleaseResource(h);
285     if (ResError() != noErr) goto out;
286     return value;
287
288   out:
289     return defvalue;
290 }
291
292 void close_settings_r(void *handle) {
293     int fd;
294
295     if (handle == NULL) return;
296     fd = *(int *)handle;
297     CloseResFile(fd);
298     if (ResError() != noErr)
299         fatalbox("Close of saved session failed (%d)", ResError());
300     safefree(handle);
301 }
302
303 void del_settings(char *sessionname) {
304     OSErr error;
305     FSSpec sessfile;
306     short sessVRefNum;
307     long sessDirID;
308     Str255 psessionname;
309
310     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
311
312     c2pstrcpy(psessionname, sessionname);
313     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
314     if (error != noErr) goto out;
315
316     error = FSpDelete(&sessfile);
317     return;
318   out:
319     fatalbox("Delete session failed (%d)", error);
320 }
321
322 struct enum_settings_state {
323     short vRefNum;
324     long dirID;
325     int index;
326 };
327
328 void *enum_settings_start(void) {
329     OSErr error;
330     struct enum_settings_state *state;
331
332     state = safemalloc(sizeof(*state));
333     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
334     if (error != noErr) {
335         safefree(state);
336         return NULL;
337     }
338     state->index = 1;
339     return state;
340 }
341
342 char *enum_settings_next(void *handle, char *buffer, int buflen) {
343     struct enum_settings_state *e = handle;
344     CInfoPBRec pb;
345     OSErr error = noErr;
346     Str255 name;
347
348     if (e == NULL) return NULL;
349     do {
350         pb.hFileInfo.ioNamePtr = name;
351         pb.hFileInfo.ioVRefNum = e->vRefNum;
352         pb.hFileInfo.ioDirID = e->dirID;
353         pb.hFileInfo.ioFDirIndex = e->index++;
354         error = PBGetCatInfoSync(&pb);
355         if (error != noErr) return NULL;
356     } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
357                pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
358                pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
359                name[0] < buflen));
360
361     p2cstrcpy(buffer, name);
362     return buffer;
363 }
364
365 void enum_settings_finish(void *handle) {
366
367     safefree(handle);
368 }
369
370 #define SEED_SIZE 512
371
372 void read_random_seed(noise_consumer_t consumer)
373 {
374     short puttyVRefNum;
375     long puttyDirID;
376     OSErr error;
377     char buf[SEED_SIZE];
378     short refnum;
379     long count = SEED_SIZE;
380
381     if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
382         return;
383     if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
384                 &refnum) != noErr)
385         return;
386     error = FSRead(refnum, &count, buf);
387     if (error != noErr && error != eofErr)
388         return;
389     (*consumer)(buf, count);
390     FSClose(refnum);
391 }
392
393 void write_random_seed(void *data, int len)
394 {
395     short puttyVRefNum, tmpVRefNum;
396     long puttyDirID, tmpDirID;
397     OSErr error;
398     FSSpec dstfile, tmpfile;
399     short refnum;
400     long count = len;
401
402     if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
403         return;
404
405     error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
406                          &dstfile);
407     if (error != noErr && error != fnfErr) return;
408
409     /* Create a temporary file to save to first. */
410     error = FindFolder(puttyVRefNum, kTemporaryFolderType, kCreateFolder,
411                        &tmpVRefNum, &tmpDirID);
412     if (error != noErr) return;
413     error = FSMakeFSSpec(tmpVRefNum, tmpDirID, "\pPuTTY Random Seed",
414                          &tmpfile);
415     if (error != noErr && error != fnfErr) return;
416     if (error == noErr) {
417         error = FSpDelete(&tmpfile);
418         if (error != noErr) return;
419     }
420     error = FSpCreate(&tmpfile, PUTTY_CREATOR, SEED_TYPE, smRoman);
421     if (error != noErr) return;
422
423     if (FSpOpenDF(&tmpfile, fsWrPerm, &refnum) != noErr) goto fail;
424
425     if (FSWrite(refnum, &count, data) != noErr) goto fail2;
426     if (FSClose(refnum) != noErr) goto fail;
427
428     if (FSpExchangeFiles(&tmpfile, &dstfile) != noErr) goto fail;
429     if (FSpDelete(&tmpfile) != noErr) return;
430
431     return;
432     
433   fail2:
434     FSClose(refnum);
435   fail:
436     FSpDelete(&tmpfile);
437 }
438
439 /*
440  * Emacs magic:
441  * Local Variables:
442  * c-file-style: "simon"
443  * End:
444  */