Correct an incorrect black pixel in the PuTTY icon that's been annoying me
[sgt/putty] / mac / macstore.c
CommitLineData
604379f1 1/* $Id: macstore.c,v 1.9 2003/01/18 12:03:28 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')
0c4b7799 22#define SEED_TYPE FOUR_CHAR_CODE('Seed')
d082ac49 23
24
d082ac49 25OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
26
27/*
28 * We store each session as a file in the "PuTTY" sub-directory of the
29 * preferences folder. Each (key,value) pair is stored as a resource.
30 */
31
0c4b7799 32OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
33{
d082ac49 34 OSErr error = noErr;
35 short prefVRefNum;
0c4b7799 36 FSSpec puttydir;
37 long prefDirID, puttyDirID;
d082ac49 38
39 error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
40 &prefVRefNum, &prefDirID);
41 if (error != noErr) goto out;
42
43 error = FSMakeFSSpec(prefVRefNum, prefDirID, "\pPuTTY", &puttydir);
44 if (error != noErr && error != fnfErr) goto out;
45 error = FSpGetDirID(&puttydir, &puttyDirID, makeit);
46 if (error != noErr) goto out;
47
0c4b7799 48 *pVRefNum = prefVRefNum;
49 *pDirID = puttyDirID;
50
51 out:
52 return error;
53}
54
55OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
56 OSErr error = noErr;
57 short puttyVRefNum;
58 FSSpec sessdir;
59 long puttyDirID, sessDirID;
60
61 error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
62 if (error != noErr) goto out;
63 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
d082ac49 64 &sessdir);
65 if (error != noErr && error != fnfErr) goto out;
66 error = FSpGetDirID(&sessdir, &sessDirID, makeit);
67 if (error != noErr) goto out;
68
0c4b7799 69 *pVRefNum = puttyVRefNum;
d082ac49 70 *pDirID = sessDirID;
71
72 out:
73 return error;
74}
75
76OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
77 CInfoPBRec pb;
78 OSErr error = noErr;
79
80 pb.dirInfo.ioNamePtr = f->name;
81 pb.dirInfo.ioVRefNum = f->vRefNum;
82 pb.dirInfo.ioDrDirID = f->parID;
83 pb.dirInfo.ioFDirIndex = 0;
84 error = PBGetCatInfoSync(&pb);
85 if (error == fnfErr && makeit)
86 return FSpDirCreate(f, smSystemScript, idp);
87 if (error != noErr) goto out;
88 if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
89 error = dirNFErr;
90 goto out;
91 }
92 *idp = pb.dirInfo.ioDrDirID;
93
94 out:
95 return error;
96}
97
98struct write_settings {
99 int fd;
100 FSSpec tmpfile;
101 FSSpec dstfile;
102};
103
f5d2d791 104void *open_settings_w(char const *sessionname) {
d082ac49 105 short sessVRefNum, tmpVRefNum;
106 long sessDirID, tmpDirID;
d082ac49 107 OSErr error;
108 Str255 psessionname;
109 struct write_settings *ws;
110
111 ws = safemalloc(sizeof *ws);
112 error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
113 if (error != noErr) goto out;
114
115 c2pstrcpy(psessionname, sessionname);
116 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &ws->dstfile);
117 if (error != noErr && error != fnfErr) goto out;
118 if (error == fnfErr) {
119 FSpCreateResFile(&ws->dstfile, PUTTY_CREATOR, SESS_TYPE,
120 smSystemScript);
121 if ((error = ResError()) != noErr) goto out;
122 }
123
124 /* Create a temporary file to save to first. */
125 error = FindFolder(sessVRefNum, kTemporaryFolderType, kCreateFolder,
126 &tmpVRefNum, &tmpDirID);
127 if (error != noErr) goto out;
128 error = FSMakeFSSpec(tmpVRefNum, tmpDirID, psessionname, &ws->tmpfile);
129 if (error != noErr && error != fnfErr) goto out;
130 if (error == noErr) {
131 error = FSpDelete(&ws->tmpfile);
132 if (error != noErr) goto out;
133 }
134 FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
135 if ((error = ResError()) != noErr) goto out;
136
137 ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
138 if (ws->fd == -1) {error = ResError(); goto out;}
139
140 return ws;
141
142 out:
143 safefree(ws);
144 fatalbox("Failed to open session for write (%d)", error);
145}
146
f5d2d791 147void write_setting_s(void *handle, char const *key, char const *value) {
d082ac49 148 int fd = *(int *)handle;
149 Handle h;
150 int id;
803efcdf 151 OSErr error;
d082ac49 152
153 UseResFile(fd);
154 if (ResError() != noErr)
155 fatalbox("Failed to open saved session (%d)", ResError());
156
157 error = PtrToHand(value, &h, strlen(value));
158 if (error != noErr)
159 fatalbox("Failed to allocate memory");
160 /* Put the data in a resource. */
161 id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
162 if (ResError() != noErr)
163 fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
164 addresource(h, FOUR_CHAR_CODE('TEXT'), id, key);
165 if (ResError() != noErr)
166 fatalbox("Failed to add resource %s (%d)", key, ResError());
167}
168
f5d2d791 169void write_setting_i(void *handle, char const *key, int value) {
d082ac49 170 int fd = *(int *)handle;
171 Handle h;
172 int id;
173 OSErr error;
174
175 UseResFile(fd);
176 if (ResError() != noErr)
177 fatalbox("Failed to open saved session (%d)", ResError());
178
179 /* XXX assume all systems have the same "int" format */
180 error = PtrToHand(&value, &h, sizeof(int));
181 if (error != noErr)
182 fatalbox("Failed to allocate memory (%d)", error);
183
184 /* Put the data in a resource. */
185 id = Unique1ID(FOUR_CHAR_CODE('Int '));
186 if (ResError() != noErr)
187 fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
188 addresource(h, FOUR_CHAR_CODE('Int '), id, key);
189 if (ResError() != noErr)
190 fatalbox("Failed to add resource %s (%d)", key, ResError());
191}
192
193void close_settings_w(void *handle) {
194 struct write_settings *ws = handle;
195 OSErr error;
196
197 CloseResFile(ws->fd);
198 if ((error = ResError()) != noErr)
199 goto out;
200 error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
201 if (error != noErr) goto out;
202 error = FSpDelete(&ws->tmpfile);
203 if (error != noErr) goto out;
204 return;
205
206 out:
207 fatalbox("Close of saved session failed (%d)", error);
208 safefree(handle);
209}
210
f5d2d791 211void *open_settings_r(char const *sessionname)
ce283213 212{
d082ac49 213 short sessVRefNum;
214 long sessDirID;
215 FSSpec sessfile;
216 OSErr error;
217 Str255 psessionname;
d082ac49 218
219 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
220
221 c2pstrcpy(psessionname, sessionname);
222 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
223 if (error != noErr) goto out;
ce283213 224 return open_settings_r_fsp(&sessfile);
225
226 out:
227 return NULL;
228}
229
230void *open_settings_r_fsp(FSSpec *sessfile)
231{
232 OSErr error;
233 int fd;
234 int *handle;
235
236 fd = FSpOpenResFile(sessfile, fsRdPerm);
d082ac49 237 if (fd == 0) {error = ResError(); goto out;}
238
239 handle = safemalloc(sizeof *handle);
240 *handle = fd;
241 return handle;
242
243 out:
244 return NULL;
245}
246
f5d2d791 247char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
d082ac49 248 int fd;
249 Handle h;
086efcde 250 size_t len;
d082ac49 251
252 if (handle == NULL) goto out;
253 fd = *(int *)handle;
254 UseResFile(fd);
255 if (ResError() != noErr) goto out;
256 h = get1namedresource(FOUR_CHAR_CODE('TEXT'), key);
257 if (h == NULL) goto out;
258
086efcde 259 len = GetHandleSize(h);
260 if (len + 1 > buflen) goto out;
261 memcpy(buffer, *h, len);
262 buffer[len] = '\0';
263
d082ac49 264 ReleaseResource(h);
265 if (ResError() != noErr) goto out;
266 return buffer;
267
268 out:
269 return NULL;
270}
271
f5d2d791 272int read_setting_i(void *handle, char const *key, int defvalue) {
d082ac49 273 int fd;
274 Handle h;
d082ac49 275 int value;
276
277 if (handle == NULL) goto out;
278 fd = *(int *)handle;
279 UseResFile(fd);
280 if (ResError() != noErr) goto out;
281 h = get1namedresource(FOUR_CHAR_CODE('Int '), key);
282 if (h == NULL) goto out;
283 value = *(int *)*h;
284 ReleaseResource(h);
285 if (ResError() != noErr) goto out;
286 return value;
287
288 out:
289 return defvalue;
290}
291
292void close_settings_r(void *handle) {
293 int fd;
294
295 if (handle == NULL) return;
296 fd = *(int *)handle;
297 CloseResFile(fd);
298 if (ResError() != noErr)
299 fatalbox("Close of saved session failed (%d)", ResError());
300 safefree(handle);
301}
302
f5d2d791 303void del_settings(char const *sessionname) {
d082ac49 304 OSErr error;
305 FSSpec sessfile;
306 short sessVRefNum;
307 long sessDirID;
308 Str255 psessionname;
309
310 error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
311
312 c2pstrcpy(psessionname, sessionname);
313 error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
314 if (error != noErr) goto out;
315
316 error = FSpDelete(&sessfile);
317 return;
318 out:
319 fatalbox("Delete session failed (%d)", error);
320}
321
322struct enum_settings_state {
323 short vRefNum;
324 long dirID;
325 int index;
326};
327
328void *enum_settings_start(void) {
329 OSErr error;
330 struct enum_settings_state *state;
331
332 state = safemalloc(sizeof(*state));
333 error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
334 if (error != noErr) {
335 safefree(state);
336 return NULL;
337 }
338 state->index = 1;
339 return state;
340}
341
342char *enum_settings_next(void *handle, char *buffer, int buflen) {
343 struct enum_settings_state *e = handle;
344 CInfoPBRec pb;
345 OSErr error = noErr;
346 Str255 name;
347
348 if (e == NULL) return NULL;
349 do {
350 pb.hFileInfo.ioNamePtr = name;
351 pb.hFileInfo.ioVRefNum = e->vRefNum;
352 pb.hFileInfo.ioDirID = e->dirID;
353 pb.hFileInfo.ioFDirIndex = e->index++;
354 error = PBGetCatInfoSync(&pb);
355 if (error != noErr) return NULL;
356 } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
357 pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
358 pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
359 name[0] < buflen));
360
361 p2cstrcpy(buffer, name);
362 return buffer;
363}
364
365void enum_settings_finish(void *handle) {
366
367 safefree(handle);
368}
369
0c4b7799 370#define SEED_SIZE 512
371
372void read_random_seed(noise_consumer_t consumer)
373{
374 short puttyVRefNum;
375 long puttyDirID;
376 OSErr error;
377 char buf[SEED_SIZE];
378 short refnum;
379 long count = SEED_SIZE;
380
381 if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
382 return;
383 if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
384 &refnum) != noErr)
385 return;
386 error = FSRead(refnum, &count, buf);
387 if (error != noErr && error != eofErr)
388 return;
389 (*consumer)(buf, count);
390 FSClose(refnum);
391}
392
604379f1 393/*
394 * We don't bother with the usual FSpExchangeFiles dance here because
395 * it doesn't really matter if the old random seed gets lost.
396 */
0c4b7799 397void write_random_seed(void *data, int len)
398{
604379f1 399 short puttyVRefNum;
400 long puttyDirID;
0c4b7799 401 OSErr error;
604379f1 402 FSSpec dstfile;
0c4b7799 403 short refnum;
404 long count = len;
405
406 if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
407 return;
408
409 error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
410 &dstfile);
604379f1 411 if (error == fnfErr)
412 error = FSpCreate(&dstfile, PUTTY_CREATOR, SEED_TYPE, smRoman);
0c4b7799 413 if (error != noErr) return;
0c4b7799 414
604379f1 415 if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
0c4b7799 416
604379f1 417 FSWrite(refnum, &count, data);
0c4b7799 418
0c4b7799 419 FSClose(refnum);
604379f1 420 return;
0c4b7799 421}
d082ac49 422
423/*
424 * Emacs magic:
425 * Local Variables:
426 * c-file-style: "simon"
427 * End:
428 */