Add an "open" command to the "file" (now "session") menu on the Mac to
[u/mdw/putty] / mac / macstore.c
CommitLineData
ce283213 1/* $Id: macstore.c,v 1.6 2002/12/30 18:21:17 ben Exp $ */
d082ac49 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"
ce283213 18#include "mac.h"
d082ac49 19
20#define PUTTY_CREATOR FOUR_CHAR_CODE('pTTY')
21#define SESS_TYPE FOUR_CHAR_CODE('Sess')
22
23
d082ac49 24OSErr 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
31OSErr 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
59OSErr 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
81struct write_settings {
82 int fd;
83 FSSpec tmpfile;
84 FSSpec dstfile;
85};
86
87void *open_settings_w(char *sessionname) {
88 short sessVRefNum, tmpVRefNum;
89 long sessDirID, tmpDirID;
d082ac49 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
130void write_setting_s(void *handle, char *key, char *value) {
131 int fd = *(int *)handle;
132 Handle h;
133 int id;
803efcdf 134 OSErr error;
d082ac49 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
152void 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
176void 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
ce283213 194void *open_settings_r(char *sessionname)
195{
d082ac49 196 short sessVRefNum;
197 long sessDirID;
198 FSSpec sessfile;
199 OSErr error;
200 Str255 psessionname;
d082ac49 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;
ce283213 207 return open_settings_r_fsp(&sessfile);
208
209 out:
210 return NULL;
211}
212
213void *open_settings_r_fsp(FSSpec *sessfile)
214{
215 OSErr error;
216 int fd;
217 int *handle;
218
219 fd = FSpOpenResFile(sessfile, fsRdPerm);
d082ac49 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
d082ac49 230char *read_setting_s(void *handle, char *key, char *buffer, int buflen) {
231 int fd;
232 Handle h;
086efcde 233 size_t len;
d082ac49 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
086efcde 242 len = GetHandleSize(h);
243 if (len + 1 > buflen) goto out;
244 memcpy(buffer, *h, len);
245 buffer[len] = '\0';
246
d082ac49 247 ReleaseResource(h);
248 if (ResError() != noErr) goto out;
249 return buffer;
250
251 out:
252 return NULL;
253}
254
255int read_setting_i(void *handle, char *key, int defvalue) {
256 int fd;
257 Handle h;
d082ac49 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
275void 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
286void 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
305struct enum_settings_state {
306 short vRefNum;
307 long dirID;
308 int index;
309};
310
311void *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
325char *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
348void 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 */