]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
Tentative merge of ben-mac-port (only dead for three years!) into the trunk.
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.1 2002/11/19 02:13:46 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
19 #define PUTTY_CREATOR   FOUR_CHAR_CODE('pTTY')
20 #define SESS_TYPE       FOUR_CHAR_CODE('Sess')
21
22
23 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID);
24 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
25
26 /*
27  * We store each session as a file in the "PuTTY" sub-directory of the
28  * preferences folder.  Each (key,value) pair is stored as a resource.
29  */
30
31 OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
32     OSErr error = noErr;
33     short prefVRefNum;
34     FSSpec puttydir, sessdir;
35     long prefDirID, puttyDirID, sessDirID;
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     error = FSMakeFSSpec(prefVRefNum, puttyDirID, "\pSaved Sessions",
47                          &sessdir);
48     if (error != noErr && error != fnfErr) goto out;
49     error = FSpGetDirID(&sessdir, &sessDirID, makeit);
50     if (error != noErr) goto out;
51
52     *pVRefNum = prefVRefNum;
53     *pDirID = sessDirID;
54
55   out:
56     return error;
57 }
58
59 OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
60     CInfoPBRec pb;
61     OSErr error = noErr;
62
63     pb.dirInfo.ioNamePtr = f->name;
64     pb.dirInfo.ioVRefNum = f->vRefNum;
65     pb.dirInfo.ioDrDirID = f->parID;
66     pb.dirInfo.ioFDirIndex = 0;
67     error = PBGetCatInfoSync(&pb);
68     if (error == fnfErr && makeit)
69         return FSpDirCreate(f, smSystemScript, idp);
70     if (error != noErr) goto out;
71     if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
72         error = dirNFErr;
73         goto out;
74     }
75     *idp = pb.dirInfo.ioDrDirID;
76
77   out:
78     return error;
79 }
80
81 struct write_settings {
82     int fd;
83     FSSpec tmpfile;
84     FSSpec dstfile;
85 };
86
87 void *open_settings_w(char *sessionname) {
88     short sessVRefNum, tmpVRefNum;
89     long sessDirID, tmpDirID;
90     FSSpec sessfile;
91     OSErr error;
92     Str255 psessionname;
93     struct write_settings *ws;
94     
95     ws = safemalloc(sizeof *ws);
96     error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
97     if (error != noErr) goto out;
98
99     c2pstrcpy(psessionname, sessionname);
100     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &ws->dstfile);
101     if (error != noErr && error != fnfErr) goto out;
102     if (error == fnfErr) {
103         FSpCreateResFile(&ws->dstfile, PUTTY_CREATOR, SESS_TYPE,
104                          smSystemScript);
105         if ((error = ResError()) != noErr) goto out;
106     }
107
108     /* Create a temporary file to save to first. */
109     error = FindFolder(sessVRefNum, kTemporaryFolderType, kCreateFolder,
110                        &tmpVRefNum, &tmpDirID);
111     if (error != noErr) goto out;
112     error = FSMakeFSSpec(tmpVRefNum, tmpDirID, psessionname, &ws->tmpfile);
113     if (error != noErr && error != fnfErr) goto out;
114     if (error == noErr) {
115         error = FSpDelete(&ws->tmpfile);
116         if (error != noErr) goto out;
117     }
118     FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
119     if ((error = ResError()) != noErr) goto out;
120
121     ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
122     if (ws->fd == -1) {error = ResError(); goto out;}
123
124     return ws;
125
126   out:
127     safefree(ws);
128     fatalbox("Failed to open session for write (%d)", error);
129 }
130
131 void write_setting_s(void *handle, char *key, char *value) {
132     int fd = *(int *)handle;
133     Handle h;
134     int id;
135     OSErr error;
136
137     UseResFile(fd);
138     if (ResError() != noErr)
139         fatalbox("Failed to open saved session (%d)", ResError());
140
141     error = PtrToHand(value, &h, strlen(value));
142     if (error != noErr)
143         fatalbox("Failed to allocate memory");
144     /* Put the data in a resource. */
145     id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
146     if (ResError() != noErr)
147         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
148     addresource(h, FOUR_CHAR_CODE('TEXT'), id, key);
149     if (ResError() != noErr)
150         fatalbox("Failed to add resource %s (%d)", key, ResError());
151 }
152
153 void write_setting_i(void *handle, char *key, int value) {
154     int fd = *(int *)handle;
155     Handle h;
156     int id;
157     OSErr error;
158
159     UseResFile(fd);
160     if (ResError() != noErr)
161         fatalbox("Failed to open saved session (%d)", ResError());
162
163     /* XXX assume all systems have the same "int" format */
164     error = PtrToHand(&value, &h, sizeof(int));
165     if (error != noErr)
166         fatalbox("Failed to allocate memory (%d)", error);
167
168     /* Put the data in a resource. */
169     id = Unique1ID(FOUR_CHAR_CODE('Int '));
170     if (ResError() != noErr)
171         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
172     addresource(h, FOUR_CHAR_CODE('Int '), id, key);
173     if (ResError() != noErr)
174         fatalbox("Failed to add resource %s (%d)", key, ResError());
175 }
176
177 void close_settings_w(void *handle) {
178     struct write_settings *ws = handle;
179     OSErr error;
180
181     CloseResFile(ws->fd);
182     if ((error = ResError()) != noErr)
183         goto out;
184     error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
185     if (error != noErr) goto out;
186     error = FSpDelete(&ws->tmpfile);
187     if (error != noErr) goto out;
188     return;
189
190   out:
191     fatalbox("Close of saved session failed (%d)", error);
192     safefree(handle);
193 }
194
195 void *open_settings_r(char *sessionname) {
196     short sessVRefNum;
197     long sessDirID;
198     FSSpec sessfile;
199     OSErr error;
200     Str255 psessionname;
201     int fd;
202     int *handle;
203
204     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
205
206     c2pstrcpy(psessionname, sessionname);
207     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
208     if (error != noErr) goto out;
209     fd = FSpOpenResFile(&sessfile, fsRdPerm);
210     if (fd == 0) {error = ResError(); goto out;}
211
212     handle = safemalloc(sizeof *handle);
213     *handle = fd;
214     return handle;
215
216   out:
217     return NULL;
218 }
219
220
221 char *read_setting_s(void *handle, char *key, char *buffer, int buflen) {
222     int fd;
223     Handle h;
224     OSErr error;
225
226     if (handle == NULL) goto out;
227     fd = *(int *)handle;
228     UseResFile(fd);
229     if (ResError() != noErr) goto out;
230     h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
231     if (h == NULL) goto out;
232
233     if (GetHandleSize(h) > buflen) goto out;
234     p2cstrcpy(buffer, (StringPtr)*h);
235     ReleaseResource(h);
236     if (ResError() != noErr) goto out;
237     return buffer;
238
239   out:
240     return NULL;
241 }
242
243 int read_setting_i(void *handle, char *key, int defvalue) {
244     int fd;
245     Handle h;
246     OSErr error;
247     int value;
248
249     if (handle == NULL) goto out;
250     fd = *(int *)handle;
251     UseResFile(fd);
252     if (ResError() != noErr) goto out;
253     h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
254     if (h == NULL) goto out;
255     value = *(int *)*h;
256     ReleaseResource(h);
257     if (ResError() != noErr) goto out;
258     return value;
259
260   out:
261     return defvalue;
262 }
263
264 void close_settings_r(void *handle) {
265     int fd;
266
267     if (handle == NULL) return;
268     fd = *(int *)handle;
269     CloseResFile(fd);
270     if (ResError() != noErr)
271         fatalbox("Close of saved session failed (%d)", ResError());
272     safefree(handle);
273 }
274
275 void del_settings(char *sessionname) {
276     OSErr error;
277     FSSpec sessfile;
278     short sessVRefNum;
279     long sessDirID;
280     Str255 psessionname;
281
282     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
283
284     c2pstrcpy(psessionname, sessionname);
285     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
286     if (error != noErr) goto out;
287
288     error = FSpDelete(&sessfile);
289     return;
290   out:
291     fatalbox("Delete session failed (%d)", error);
292 }
293
294 struct enum_settings_state {
295     short vRefNum;
296     long dirID;
297     int index;
298 };
299
300 void *enum_settings_start(void) {
301     OSErr error;
302     struct enum_settings_state *state;
303
304     state = safemalloc(sizeof(*state));
305     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
306     if (error != noErr) {
307         safefree(state);
308         return NULL;
309     }
310     state->index = 1;
311     return state;
312 }
313
314 char *enum_settings_next(void *handle, char *buffer, int buflen) {
315     struct enum_settings_state *e = handle;
316     CInfoPBRec pb;
317     OSErr error = noErr;
318     Str255 name;
319
320     if (e == NULL) return NULL;
321     do {
322         pb.hFileInfo.ioNamePtr = name;
323         pb.hFileInfo.ioVRefNum = e->vRefNum;
324         pb.hFileInfo.ioDirID = e->dirID;
325         pb.hFileInfo.ioFDirIndex = e->index++;
326         error = PBGetCatInfoSync(&pb);
327         if (error != noErr) return NULL;
328     } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
329                pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
330                pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
331                name[0] < buflen));
332
333     p2cstrcpy(buffer, name);
334     return buffer;
335 }
336
337 void enum_settings_finish(void *handle) {
338
339     safefree(handle);
340 }
341
342
343 /*
344  * Emacs magic:
345  * Local Variables:
346  * c-file-style: "simon"
347  * End:
348  */