Tentative merge of ben-mac-port (only dead for three years!) into the trunk.
[u/mdw/putty] / 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 */