]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
5764e198439128c75b44a26f65e9dd683fe7edb1
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.3 2002/12/28 22:22:43 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     OSErr error;
91     Str255 psessionname;
92     struct write_settings *ws;
93     
94     ws = safemalloc(sizeof *ws);
95     error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
96     if (error != noErr) goto out;
97
98     c2pstrcpy(psessionname, sessionname);
99     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &ws->dstfile);
100     if (error != noErr && error != fnfErr) goto out;
101     if (error == fnfErr) {
102         FSpCreateResFile(&ws->dstfile, PUTTY_CREATOR, SESS_TYPE,
103                          smSystemScript);
104         if ((error = ResError()) != noErr) goto out;
105     }
106
107     /* Create a temporary file to save to first. */
108     error = FindFolder(sessVRefNum, kTemporaryFolderType, kCreateFolder,
109                        &tmpVRefNum, &tmpDirID);
110     if (error != noErr) goto out;
111     error = FSMakeFSSpec(tmpVRefNum, tmpDirID, psessionname, &ws->tmpfile);
112     if (error != noErr && error != fnfErr) goto out;
113     if (error == noErr) {
114         error = FSpDelete(&ws->tmpfile);
115         if (error != noErr) goto out;
116     }
117     FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
118     if ((error = ResError()) != noErr) goto out;
119
120     ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
121     if (ws->fd == -1) {error = ResError(); goto out;}
122
123     return ws;
124
125   out:
126     safefree(ws);
127     fatalbox("Failed to open session for write (%d)", error);
128 }
129
130 void write_setting_s(void *handle, char *key, char *value) {
131     int fd = *(int *)handle;
132     Handle h;
133     int id;
134     OSErr error;
135
136     UseResFile(fd);
137     if (ResError() != noErr)
138         fatalbox("Failed to open saved session (%d)", ResError());
139
140     error = PtrToHand(value, &h, strlen(value));
141     if (error != noErr)
142         fatalbox("Failed to allocate memory");
143     /* Put the data in a resource. */
144     id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
145     if (ResError() != noErr)
146         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
147     addresource(h, FOUR_CHAR_CODE('TEXT'), id, key);
148     if (ResError() != noErr)
149         fatalbox("Failed to add resource %s (%d)", key, ResError());
150 }
151
152 void write_setting_i(void *handle, char *key, int value) {
153     int fd = *(int *)handle;
154     Handle h;
155     int id;
156     OSErr error;
157
158     UseResFile(fd);
159     if (ResError() != noErr)
160         fatalbox("Failed to open saved session (%d)", ResError());
161
162     /* XXX assume all systems have the same "int" format */
163     error = PtrToHand(&value, &h, sizeof(int));
164     if (error != noErr)
165         fatalbox("Failed to allocate memory (%d)", error);
166
167     /* Put the data in a resource. */
168     id = Unique1ID(FOUR_CHAR_CODE('Int '));
169     if (ResError() != noErr)
170         fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
171     addresource(h, FOUR_CHAR_CODE('Int '), id, key);
172     if (ResError() != noErr)
173         fatalbox("Failed to add resource %s (%d)", key, ResError());
174 }
175
176 void close_settings_w(void *handle) {
177     struct write_settings *ws = handle;
178     OSErr error;
179
180     CloseResFile(ws->fd);
181     if ((error = ResError()) != noErr)
182         goto out;
183     error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
184     if (error != noErr) goto out;
185     error = FSpDelete(&ws->tmpfile);
186     if (error != noErr) goto out;
187     return;
188
189   out:
190     fatalbox("Close of saved session failed (%d)", error);
191     safefree(handle);
192 }
193
194 void *open_settings_r(char *sessionname) {
195     short sessVRefNum;
196     long sessDirID;
197     FSSpec sessfile;
198     OSErr error;
199     Str255 psessionname;
200     int fd;
201     int *handle;
202
203     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
204
205     c2pstrcpy(psessionname, sessionname);
206     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
207     if (error != noErr) goto out;
208     fd = FSpOpenResFile(&sessfile, fsRdPerm);
209     if (fd == 0) {error = ResError(); goto out;}
210
211     handle = safemalloc(sizeof *handle);
212     *handle = fd;
213     return handle;
214
215   out:
216     return NULL;
217 }
218
219
220 char *read_setting_s(void *handle, char *key, char *buffer, int buflen) {
221     int fd;
222     Handle h;
223     OSErr error;
224     size_t len;
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     len = GetHandleSize(h);
234     if (len + 1 > buflen) goto out;
235     memcpy(buffer, *h, len);
236     buffer[len] = '\0';
237
238     ReleaseResource(h);
239     if (ResError() != noErr) goto out;
240     return buffer;
241
242   out:
243     return NULL;
244 }
245
246 int read_setting_i(void *handle, char *key, int defvalue) {
247     int fd;
248     Handle h;
249     int value;
250
251     if (handle == NULL) goto out;
252     fd = *(int *)handle;
253     UseResFile(fd);
254     if (ResError() != noErr) goto out;
255     h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
256     if (h == NULL) goto out;
257     value = *(int *)*h;
258     ReleaseResource(h);
259     if (ResError() != noErr) goto out;
260     return value;
261
262   out:
263     return defvalue;
264 }
265
266 void close_settings_r(void *handle) {
267     int fd;
268
269     if (handle == NULL) return;
270     fd = *(int *)handle;
271     CloseResFile(fd);
272     if (ResError() != noErr)
273         fatalbox("Close of saved session failed (%d)", ResError());
274     safefree(handle);
275 }
276
277 void del_settings(char *sessionname) {
278     OSErr error;
279     FSSpec sessfile;
280     short sessVRefNum;
281     long sessDirID;
282     Str255 psessionname;
283
284     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
285
286     c2pstrcpy(psessionname, sessionname);
287     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
288     if (error != noErr) goto out;
289
290     error = FSpDelete(&sessfile);
291     return;
292   out:
293     fatalbox("Delete session failed (%d)", error);
294 }
295
296 struct enum_settings_state {
297     short vRefNum;
298     long dirID;
299     int index;
300 };
301
302 void *enum_settings_start(void) {
303     OSErr error;
304     struct enum_settings_state *state;
305
306     state = safemalloc(sizeof(*state));
307     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
308     if (error != noErr) {
309         safefree(state);
310         return NULL;
311     }
312     state->index = 1;
313     return state;
314 }
315
316 char *enum_settings_next(void *handle, char *buffer, int buflen) {
317     struct enum_settings_state *e = handle;
318     CInfoPBRec pb;
319     OSErr error = noErr;
320     Str255 name;
321
322     if (e == NULL) return NULL;
323     do {
324         pb.hFileInfo.ioNamePtr = name;
325         pb.hFileInfo.ioVRefNum = e->vRefNum;
326         pb.hFileInfo.ioDirID = e->dirID;
327         pb.hFileInfo.ioFDirIndex = e->index++;
328         error = PBGetCatInfoSync(&pb);
329         if (error != noErr) return NULL;
330     } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
331                pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
332                pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
333                name[0] < buflen));
334
335     p2cstrcpy(buffer, name);
336     return buffer;
337 }
338
339 void enum_settings_finish(void *handle) {
340
341     safefree(handle);
342 }
343
344
345 /*
346  * Emacs magic:
347  * Local Variables:
348  * c-file-style: "simon"
349  * End:
350  */