]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macstore.c
Set the default directory to somewhere useful (the PuTTY saved sessions
[PuTTY.git] / mac / macstore.c
1 /* $Id: macstore.c,v 1.6 2002/12/30 18:21:17 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
23
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 {
196     short sessVRefNum;
197     long sessDirID;
198     FSSpec sessfile;
199     OSErr error;
200     Str255 psessionname;
201
202     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
203
204     c2pstrcpy(psessionname, sessionname);
205     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
206     if (error != noErr) goto out;
207     return open_settings_r_fsp(&sessfile);
208
209   out:
210     return NULL;
211 }
212
213 void *open_settings_r_fsp(FSSpec *sessfile)
214 {
215     OSErr error;
216     int fd;
217     int *handle;
218
219     fd = FSpOpenResFile(sessfile, fsRdPerm);
220     if (fd == 0) {error = ResError(); goto out;}
221
222     handle = safemalloc(sizeof *handle);
223     *handle = fd;
224     return handle;
225
226   out:
227     return NULL;
228 }
229
230 char *read_setting_s(void *handle, char *key, char *buffer, int buflen) {
231     int fd;
232     Handle h;
233     size_t len;
234
235     if (handle == NULL) goto out;
236     fd = *(int *)handle;
237     UseResFile(fd);
238     if (ResError() != noErr) goto out;
239     h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
240     if (h == NULL) goto out;
241
242     len = GetHandleSize(h);
243     if (len + 1 > buflen) goto out;
244     memcpy(buffer, *h, len);
245     buffer[len] = '\0';
246
247     ReleaseResource(h);
248     if (ResError() != noErr) goto out;
249     return buffer;
250
251   out:
252     return NULL;
253 }
254
255 int read_setting_i(void *handle, char *key, int defvalue) {
256     int fd;
257     Handle h;
258     int value;
259
260     if (handle == NULL) goto out;
261     fd = *(int *)handle;
262     UseResFile(fd);
263     if (ResError() != noErr) goto out;
264     h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
265     if (h == NULL) goto out;
266     value = *(int *)*h;
267     ReleaseResource(h);
268     if (ResError() != noErr) goto out;
269     return value;
270
271   out:
272     return defvalue;
273 }
274
275 void close_settings_r(void *handle) {
276     int fd;
277
278     if (handle == NULL) return;
279     fd = *(int *)handle;
280     CloseResFile(fd);
281     if (ResError() != noErr)
282         fatalbox("Close of saved session failed (%d)", ResError());
283     safefree(handle);
284 }
285
286 void del_settings(char *sessionname) {
287     OSErr error;
288     FSSpec sessfile;
289     short sessVRefNum;
290     long sessDirID;
291     Str255 psessionname;
292
293     error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
294
295     c2pstrcpy(psessionname, sessionname);
296     error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
297     if (error != noErr) goto out;
298
299     error = FSpDelete(&sessfile);
300     return;
301   out:
302     fatalbox("Delete session failed (%d)", error);
303 }
304
305 struct enum_settings_state {
306     short vRefNum;
307     long dirID;
308     int index;
309 };
310
311 void *enum_settings_start(void) {
312     OSErr error;
313     struct enum_settings_state *state;
314
315     state = safemalloc(sizeof(*state));
316     error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
317     if (error != noErr) {
318         safefree(state);
319         return NULL;
320     }
321     state->index = 1;
322     return state;
323 }
324
325 char *enum_settings_next(void *handle, char *buffer, int buflen) {
326     struct enum_settings_state *e = handle;
327     CInfoPBRec pb;
328     OSErr error = noErr;
329     Str255 name;
330
331     if (e == NULL) return NULL;
332     do {
333         pb.hFileInfo.ioNamePtr = name;
334         pb.hFileInfo.ioVRefNum = e->vRefNum;
335         pb.hFileInfo.ioDirID = e->dirID;
336         pb.hFileInfo.ioFDirIndex = e->index++;
337         error = PBGetCatInfoSync(&pb);
338         if (error != noErr) return NULL;
339     } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
340                pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
341                pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
342                name[0] < buflen));
343
344     p2cstrcpy(buffer, name);
345     return buffer;
346 }
347
348 void enum_settings_finish(void *handle) {
349
350     safefree(handle);
351 }
352
353
354 /*
355  * Emacs magic:
356  * Local Variables:
357  * c-file-style: "simon"
358  * End:
359  */