/[MITgcm]/MITgcm/tools/mpack-1.6/macmpack.c
ViewVC logotype

Contents of /MITgcm/tools/mpack-1.6/macmpack.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download)
Tue Aug 26 20:45:25 2003 UTC (20 years, 7 months ago) by edhill
Branch: MAIN
CVS Tags: checkpoint64y, checkpoint64x, checkpoint58l_post, checkpoint64z, checkpoint51k_post, checkpoint57t_post, checkpoint64q, checkpoint64p, checkpoint64s, checkpoint64r, checkpoint64u, checkpoint64t, checkpoint64w, checkpoint64v, checkpoint64i, checkpoint64h, checkpoint64k, checkpoint64j, checkpoint64m, checkpoint64l, checkpoint64o, checkpoint64n, checkpoint64a, checkpoint57o_post, checkpoint64c, checkpoint64b, checkpoint64e, checkpoint64d, checkpoint64g, checkpoint64f, checkpoint52l_pre, checkpoint52e_pre, hrcube4, checkpoint58e_post, mitgcm_mapl_00, checkpoint52n_post, checkpoint52j_post, checkpoint53d_post, checkpoint58u_post, checkpoint58w_post, checkpoint54a_pre, checkpoint51o_pre, checkpoint57m_post, checkpoint55c_post, checkpoint54e_post, checkpoint52e_post, checkpoint57s_post, checkpoint51n_pre, checkpoint54a_post, checkpoint63p, checkpoint63q, checkpoint63r, checkpoint63s, checkpoint63l, checkpoint63m, checkpoint63n, checkpoint63o, checkpoint63h, checkpoint63i, checkpoint63j, checkpoint63k, checkpoint63d, checkpoint63e, checkpoint63f, checkpoint63g, checkpoint53c_post, checkpoint63a, checkpoint63b, checkpoint63c, checkpoint57k_post, checkpoint55d_pre, checkpoint57d_post, checkpoint51l_post, checkpoint57g_post, checkpoint51q_post, checkpoint64, checkpoint65, checkpoint60, checkpoint61, checkpoint62, checkpoint63, checkpoint57b_post, checkpoint57c_pre, checkpoint51j_post, checkpoint58r_post, checkpoint55j_post, checkpoint56b_post, checkpoint57i_post, checkpoint57y_post, hrcube_1, checkpoint57e_post, checkpoint66g, checkpoint66f, checkpoint66e, checkpoint66d, checkpoint66c, checkpoint66b, checkpoint66a, checkpoint66o, checkpoint66n, checkpoint66m, checkpoint66l, checkpoint66k, checkpoint66j, checkpoint66i, checkpoint66h, branch-netcdf, checkpoint52d_pre, checkpoint52l_post, checkpoint55h_post, checkpoint58n_post, checkpoint53b_post, checkpoint58x_post, checkpoint52k_post, checkpoint52b_pre, checkpoint57g_pre, checkpoint54b_post, checkpoint53b_pre, checkpoint55b_post, checkpoint58t_post, checkpoint58h_post, checkpoint65z, checkpoint65x, checkpoint65y, checkpoint54d_post, checkpoint65r, checkpoint65s, checkpoint65p, checkpoint65q, checkpoint65v, checkpoint65w, checkpoint65t, checkpoint65u, checkpoint65j, checkpoint65k, checkpoint65h, checkpoint65i, checkpoint65n, checkpoint65o, checkpoint65l, checkpoint65m, checkpoint65b, checkpoint65c, checkpoint65a, checkpoint65f, checkpoint65g, checkpoint65d, checkpoint65e, checkpoint56c_post, checkpoint52m_post, checkpoint57y_pre, checkpoint55, checkpoint53a_post, checkpoint57f_pre, checkpoint57a_post, checkpoint54, checkpoint58q_post, checkpoint54f_post, checkpoint57v_post, checkpoint59q, checkpoint59p, checkpoint55g_post, checkpoint59r, checkpoint51o_post, checkpoint51p_post, checkpoint58j_post, checkpoint52a_pre, checkpoint59e, checkpoint59d, checkpoint59g, checkpoint59f, checkpoint59a, checkpoint55f_post, checkpoint59c, checkpoint59b, checkpoint59m, checkpoint59l, checkpoint59o, checkpoint59n, checkpoint59i, checkpoint59h, checkpoint59k, checkpoint59j, checkpoint57r_post, checkpoint59, checkpoint58, checkpoint57a_pre, checkpoint55i_post, checkpoint57, checkpoint56, checkpoint51i_post, checkpoint53, checkpoint52, checkpoint51f_post, checkpoint52d_post, eckpoint57e_pre, checkpoint51r_post, checkpoint52a_post, checkpoint57h_done, checkpoint58f_post, checkpoint52b_post, checkpoint53g_post, checkpoint52f_post, branchpoint-genmake2, checkpoint57x_post, checkpoint57n_post, checkpoint52c_post, checkpoint58d_post, checkpoint58c_post, checkpoint57w_post, checkpoint57p_post, checkpint57u_post, checkpoint57f_post, checkpoint58a_post, checkpoint51h_pre, checkpoint51l_pre, checkpoint58i_post, checkpoint57q_post, checkpoint51g_post, checkpoint58g_post, ecco_c52_e35, hrcube5, checkpoint58o_post, checkpoint57z_post, checkpoint62c, checkpoint62b, checkpoint62a, checkpoint62g, checkpoint62f, checkpoint62e, checkpoint62d, checkpoint62k, checkpoint62j, checkpoint62i, checkpoint62h, checkpoint62o, checkpoint62n, checkpoint62m, checkpoint62l, checkpoint62s, checkpoint62r, checkpoint62q, checkpoint62p, checkpoint62w, checkpoint62v, checkpoint62u, checkpoint62t, checkpoint57c_post, checkpoint62z, checkpoint62y, checkpoint62x, checkpoint58y_post, checkpoint55e_post, checkpoint58k_post, checkpoint52i_post, checkpoint52j_pre, checkpoint58v_post, checkpoint53f_post, checkpoint55a_post, checkpoint51t_post, checkpoint53d_pre, checkpoint54c_post, checkpoint58s_post, checkpoint61f, checkpoint61g, checkpoint61d, checkpoint61e, checkpoint61b, checkpoint61c, checkpoint58p_post, checkpoint61a, checkpoint61n, checkpoint61o, checkpoint61l, checkpoint61m, checkpoint61j, checkpoint61k, checkpoint61h, checkpoint61i, checkpoint61v, checkpoint61w, checkpoint61t, checkpoint61u, checkpoint61r, checkpoint61s, checkpoint61p, checkpoint61q, checkpoint51n_post, checkpoint57j_post, checkpoint61z, checkpoint61x, checkpoint61y, checkpoint58b_post, checkpoint57h_pre, checkpoint51i_pre, checkpoint58m_post, checkpoint57l_post, checkpoint52i_pre, checkpoint51u_post, checkpoint52h_pre, checkpoint52f_pre, checkpoint57h_post, hrcube_2, hrcube_3, checkpoint56a_post, checkpoint51m_post, checkpoint51s_post, checkpoint55d_post, HEAD
Branch point for: branch-nonh, branch-genmake2, tg2-branch, checkpoint51n_branch, netcdf-sm0
File MIME type: text/plain
Initial check-in of the CMU "mpack" utility.  This allows us to (portably)
send MITgcm output as MIME-encoded email messages and will be used by the
"testreport" script.  The CMU license is basically an "AS-IS" statement.

1 /* macmpack.c -- Mac user interface to mpack routines
2 *
3 * (C) Copyright 1993-1995 by Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software
7 * and its documentation for any purpose is hereby granted without fee,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear in
10 * supporting documentation, and that the name of Carnegie Mellon University
11 * not be used in advertising or publicity pertaining to distribution of the
12 * software without specific, written prior permission. Carnegie
13 * Mellon University makes no representations about the suitability of
14 * this software for any purpose. It is provided "as is" without
15 * express or implied warranty.
16 *
17 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
18 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
20 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
22 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 * SOFTWARE.
25 *
26 * NOTE: a good GUI requires a lot of work... This needs more.
27 */
28
29 #include <Folders.h>
30 #include <Script.h>
31 #include <GestaltEqu.h>
32
33 #include <stdio.h>
34 #include <time.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "version.h"
38 #include "part.h"
39 #include "macnapp.h"
40 #include "macmpack.h"
41 #include "macICTypes.h"
42 #include "macICAPI.h"
43 #include "macICKeys.h"
44
45 /* ThinkC's internal stdio functions: */
46 #include <ansi_private.h>
47
48 /* window types: */
49 #define DECODELIST 1
50 #define PREFWIN 2
51
52 /* save watch cursor */
53 Cursor watch;
54
55 /* preferences */
56 struct pref_folder *pfolder = NULL;
57 struct mpack_preferences **mpack_prefs = NULL;
58 static ICInstance icinst = NULL;
59
60 /* flag for active help window */
61 static WindowPtr helpw = NULL;
62
63 /* active decode status window */
64 static na_win *curstatwin = NULL;
65 short didchat;
66
67 /* MacTCP started: -1 = error, 1 = active, 0 = unknown */
68 static short tcpstart = 0;
69
70 /* this is used for opening TEXT files */
71 SFTypeList textList = { 'TEXT', 0, 0, 0 };
72
73 /* next two types are used in the dialog used to select files to decode
74 */
75 typedef struct filelist {
76 short vRefNum;
77 long dirID;
78 PCstr fname[65];
79 } filelist;
80 typedef struct listwin {
81 na_win win;
82 int count;
83 filelist **hflist;
84 ListHandle l;
85 } listwin;
86
87 /* this is the status window for decoding
88 */
89 typedef struct statuswin {
90 na_win win;
91 RgnHandle urgn; /* user region */
92 Rect urect; /* user rectangle */
93 Rect frect; /* frame rectangle */
94 short row; /* row at top of scroll area */
95 short nrow; /* rows of status text */
96 long size, used; /* bytes of status text & amount used */
97 Handle text; /* status text */
98 ControlHandle sb; /* scroll bar control */
99 short height, ascent; /* font height and ascent */
100 } statuswin;
101
102 /* this is for the encode window
103 */
104 typedef struct encodewin {
105 nate_win w;
106 Boolean nateon; /* cursor in Desc edit field */
107 Boolean useemail; /* sending email */
108 long partsize; /* max part size (0 = no limit) */
109 OSType ftype; /* type of file to encode */
110 FSSpec fspec; /* file to encode */
111 FSSpec ofile; /* output file */
112 } encodewin;
113
114 /* show progress
115 */
116 typedef struct progresswin {
117 natcp_win w;
118 short percent;
119 } progresswin;
120
121 /* send mail
122 */
123 typedef struct mailwin {
124 progresswin w;
125 Handle headers; /* email headers */
126 Handle envelope; /* envelope */
127 short state; /* state */
128 short remaining; /* messages remaining */
129 Boolean sending; /* flag for active SMTP task */
130 Boolean useemail; /* sending email */
131 Boolean gothost; /* got the hostname */
132 long partsize; /* max part size (0 = no limit) */
133 long dirID; /* ID for temp dir */
134 OSType ftype; /* type of file to encode */
135 FSSpec fspec; /* file to be encoded */
136 FSSpec ofile; /* output file */
137 FILE *dfile; /* desc file */
138 PCstr server[257]; /* SMTP server */
139 PCstr subj[257]; /* subject */
140 CInfoPBRec cpb;
141 } mailwin;
142
143 /* mailwin states */
144 #define MS_MACTCP 0 /* Starting MacTCP */
145 #define MS_GETHOST 1 /* Getting hostname */
146 #define MS_ENCODE 2 /* Do encoding */
147 #define MS_SENDING 3 /* Sending email */
148
149 /* some prototypes */
150 void warn(char *str);
151 void stattext(Str255, unsigned char);
152 static void do_decodefiles(na_win *);
153 static void addfile(listwin *, FSSpec *);
154 static void removefile(listwin *);
155 static short listclose(na_win *);
156 static short listmouse(na_win *, Point, short, short);
157 static short listctrl(na_win *, Point, short, short, ControlHandle);
158 static short listupdate(na_win *, Boolean);
159 static short listinit(na_win *,long *);
160 static short prefsctrl(na_win *, Point, short, short, ControlHandle);
161 static short prefsinit(na_win *, long *);
162 static void do_decode(FSSpec *);
163 static void do_encode(FSSpec *, OSType);
164 static short mainmenu(struct na_win*, WORD, WORD);
165
166 #define dwin ((listwin *) win)
167 #define swin ((statuswin *) win)
168 #define ewin ((encodewin *) win)
169 #define twin ((nate_win *) win)
170 #define prwin ((progresswin *) win)
171 #define mwin ((mailwin *) win)
172
173 /* Get a FILE* to a Macintosh file
174 ******************************* ###############################
175 * KLUDGE ALERT! KLUDGE ALERT! * # KLUDGE ALERT! KLUDGE ALERT! #
176 ******************************* ###############################
177 * Mac files are specified by name/vRefNum/dirID combo, but the portable
178 * portions of mpack use FILE* to do I/O. We need a way to get an open FILE*
179 * from a file specified by name/vRefNum/dirID. Here we use the proper Macintosh
180 * routines to open a file, then hack together a FILE* using ThinkC's internal
181 * routines. The major trouble is that we have no way to get at the FILE action
182 * procedure (fp->proc), so we need a sample FILE* to be passed in. Bleargh!
183 ******************************* ###############################
184 * KLUDGE ALERT! KLUDGE ALERT! * # KLUDGE ALERT! KLUDGE ALERT! #
185 ******************************* ###############################
186 */
187 FILE *Macopen(FILE *sample, Str255 name, short vRefNum, long dirID,
188 short binary_flag, short res_fork, SignedByte permission)
189 {
190 FILE *fp = NULL;
191 short refnum;
192 long curEOF;
193 OSErr err;
194
195 if ((!res_fork && (err = HOpen(vRefNum, dirID, name, permission, &refnum)) == noErr)
196 || (res_fork && (err = HOpenRF(vRefNum, dirID, name, permission, &refnum)) == noErr)) {
197 if ((fp = __getfile()) == NULL) {
198 FSClose(refnum);
199 } else {
200 if (permission == fsWrPerm) {
201 /* if we're writing to the file, truncate it */
202 SetEOF(refnum, curEOF = 0);
203 } else {
204 GetEOF(refnum, &curEOF);
205 }
206 fp->refnum = refnum;
207 fp->len = (fpos_t) curEOF;
208 fp->binary = binary_flag;
209 setvbuf(fp, NULL, _IOFBF, BUFSIZ);
210 fp->proc = sample->proc;
211 }
212 }
213
214 return (fp);
215 }
216
217
218 /* warn the user
219 */
220 void warn(char *str)
221 {
222 PCstr wstr[257];
223
224 CtoPCstrncpy(wstr, str, 255);
225 ParamText(P(wstr), NULL, NULL, NULL);
226 NAalert(warnALRT);
227 }
228
229 /* yell at the user
230 */
231 void yell(char *str)
232 {
233 PCstr wstr[257];
234
235 CtoPCstrncpy(wstr, str, 255);
236 ParamText(P(wstr), NULL, NULL, NULL);
237 NAalert(errorALRT);
238 }
239
240 /* chat with user
241 */
242 chat(char *str)
243 {
244 PCstr tmpstr[257];
245
246 CtoPCstrcpy(tmpstr, str);
247 stattext(P(tmpstr), 0);
248 }
249
250 /* returns NA_ALLCLOSED if appropriate, else NA_CLOSED
251 */
252 static short alldone(na_win *win)
253 {
254 if (win->next == NULL && win->afterp == NULL && (*mpack_prefs)->quit_finished
255 && RecoverHandle((Ptr) win) == (Handle) NAhead) {
256 return (NA_ALLCLOSED);
257 }
258
259 return (NA_CLOSED);
260 }
261
262 /* update procedure for status dialog box
263 */
264 static short statupdate(na_win *win, Boolean newsize)
265 {
266 RgnHandle savergn;
267 unsigned char *s;
268 short row, top;
269 Rect tmpr;
270
271 FrameRect(&swin->frect);
272 savergn = NewRgn();
273 if (savergn) {
274 GetClip(savergn);
275 SetClip(swin->urgn);
276 }
277
278 /* redraw text area */
279 HLock(swin->text);
280 s = * (unsigned char **) swin->text;
281 top = swin->urect.top;
282 for (row = 0; row < swin->row; ++row) {
283 s += s[1] + 2;
284 }
285 for (; row < swin->nrow && top + swin->height <= swin->urect.bottom; ++row) {
286 MoveTo(swin->urect.left, top + swin->ascent);
287 if (*s) TextFace(1);
288 DrawString(s + 1);
289 if (*s) TextFace(0);
290 /* advance to next string */
291 top += swin->height;
292 s += s[1] + 2;
293 }
294 HUnlock(swin->text);
295
296 if (savergn) {
297 SetClip(savergn);
298 DisposeRgn(savergn);
299 }
300
301 return (NA_NOTPROCESSED);
302 }
303
304 /* refresh status window
305 */
306 void statrefresh()
307 {
308 na_win *win = curstatwin;
309
310 Draw1Control(swin->sb);
311 statupdate(win, false);
312 }
313
314 /* add text to the status window
315 */
316 void stattext(Str255 str, unsigned char bold)
317 {
318 na_win *win = curstatwin;
319 short i, len;
320 unsigned char *s, *start;
321 RgnHandle rgn;
322 Rect tmpr;
323
324 if (!win) return;
325 didchat = 1;
326
327 /* advance to next row */
328 if (swin->height * (swin->nrow++ - swin->row)
329 >= swin->urect.bottom - swin->urect.top) {
330 SetCtlMax(swin->sb, ++swin->row);
331 SetCtlValue(swin->sb, swin->row);
332 if ((rgn = NewRgn()) != NULL) {
333 tmpr = swin->urect;
334 ScrollRect(&tmpr, 0, -swin->height, rgn);
335 DisposeRgn(rgn);
336 }
337 }
338
339 /* add the text */
340 len = * (unsigned char *) str;
341 if (swin->size - swin->used < len + 1) {
342 SetHandleSize(swin->text, swin->size * 2);
343 if (MemError() == 0) swin->size *= 2;
344 }
345 HLock(swin->text);
346 s = start = * (unsigned char **) swin->text;
347 for (i = 1; i < swin->nrow; ++i) {
348 s += s[1] + 2;
349 }
350 if (len + 2 + s < start + swin->size) {
351 *s = bold;
352 memcpy(s + 1, str, len + 1);
353 swin->used = s + len + 2 - start;
354 }
355 HUnlock(swin->text);
356 statupdate(win, false);
357 }
358
359 /* scroll the status dialog
360 */
361 static void statscroll(na_win *win, short rows)
362 {
363 RgnHandle rgn;
364
365 if ((rgn = NewRgn()) != NULL) {
366 SetCtlValue(swin->sb, swin->row += rows);
367 ScrollRect(&swin->urect, 0, - swin->height * rows, rgn);
368 EraseRgn(rgn);
369 DisposeRgn(rgn);
370 }
371 statupdate(win, false);
372 }
373
374 /* scroll bar procedure
375 */
376 static pascal void statscollbar(ControlHandle ctrlh, short part)
377 {
378 na_win *win = (na_win *) GetCRefCon(ctrlh);
379 short max, new, page;
380
381 max = GetCtlMax(ctrlh);
382 page = (swin->urect.bottom - swin->urect.top) / swin->height - 1;
383 switch (part) {
384 case inUpButton:
385 page = 1;
386 /* fall through */
387 case inPageUp:
388 if (swin->row > 0) {
389 statscroll(win, - (swin->row < page ? swin->row : page));
390 }
391 break;
392 case inDownButton:
393 page = 1;
394 /* fall through */
395 case inPageDown:
396 if (swin->row < max) {
397 statscroll(win, max - swin->row < page ? max - swin->row : page);
398 }
399 break;
400 case inThumb:
401 break;
402 }
403 }
404
405 /* control procedure for status dialog box
406 */
407 static short statctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
408 {
409 short value;
410
411 if (ctrlh == swin->sb) {
412 ctrlh = swin->sb;
413 if (item != inThumb) {
414 SetCRefCon(ctrlh, (long) win);
415 TrackControl(ctrlh, p, statscollbar);
416 } else {
417 TrackControl(ctrlh, p, nil);
418 value = GetCtlValue(ctrlh);
419 if (value != swin->row) statscroll(win, value - swin->row);
420 }
421 } else if (item == iOk) {
422 return (NA_REQCLOSE);
423 }
424
425 return (NA_NOTPROCESSED);
426 }
427
428 /* close procedure for status dialog box
429 */
430 static short statclose(na_win *win)
431 {
432 DisposeRgn(swin->urgn);
433 DisposHandle(swin->text);
434 DisposeControl(swin->sb);
435
436 return (alldone(win));
437 }
438
439 /* init procedure for status dialog box
440 */
441 static short statinit(na_win *win, long *data)
442 {
443 Rect tmpr;
444 FontInfo finfo;
445
446 /* disable OK button while working */
447 NAhiliteDItem(win->pwin, iOk, 255);
448
449 /* set up status text area & font */
450 if ((swin->urgn = NewRgn()) == NULL) return (NA_CLOSED);
451 TextFont(geneva);
452 TextSize(9);
453 GetFontInfo(&finfo);
454 swin->ascent = finfo.ascent;
455 swin->height = finfo.ascent + finfo.descent + finfo.leading;
456 NAgetDRect(win->pwin, iStatus, &swin->frect);
457 swin->urect = swin->frect;
458 InsetRect(&swin->urect, 2,
459 2 + ((swin->urect.bottom - swin->urect.top - 4) % swin->height) / 2);
460 RectRgn(swin->urgn, &swin->urect);
461
462 /* set up text storage */
463 if ((swin->text = NewHandle(swin->size = 1024)) == NULL) {
464 DisposeRgn(swin->urgn);
465 return (NA_CLOSED);
466 }
467 **(char **)swin->text = '\0';
468
469 /* set up scrollbar */
470 NAgetDRect(win->pwin, iStatScroll, &tmpr);
471 swin->sb = NewControl(win->pwin, &tmpr, "\p", true, 0, 0, 0, scrollBarProc, 0);
472 if (!swin->sb) {
473 DisposeRgn(swin->urgn);
474 DisposHandle(swin->text);
475 return (NA_CLOSED);
476 }
477
478 /* set up procedures */
479 win->closep = statclose;
480 win->ctrlp = statctrl;
481 win->updatep = statupdate;
482
483 /* keep window locked until decoding is done */
484 ++win->locks;
485 curstatwin = win;
486
487 return (NA_NOTPROCESSED);
488 }
489
490 /* process the files in the file list
491 */
492 static void do_decodefiles(na_win *win)
493 {
494 int count = dwin->count;
495 filelist *fl;
496 FILE *dfile, *tmpf;
497 extern long _ftype, _fcreator;
498 long ticks;
499 int result;
500
501 MapTypeCreator("text/plain", 0);
502 SetCursor(&watch);
503 if (NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_DEFBUTTON | NA_USERESOURCE
504 | NA_CLOSEBOX | NA_HASCONTROLS,
505 0, dstatDLOG, 0, sizeof (statuswin), statinit) == NA_CLOSED) {
506 warn("Not enough memory to decode");
507 return;
508 }
509 MoveHHi((Handle) dwin->hflist);
510 HLock((Handle) dwin->hflist);
511 fl = *dwin->hflist;
512 tmpf = tmpfile();
513 while (count--) {
514 stattext(fl->fname, 1);
515 didchat = 0;
516 if (dfile = Macopen(tmpf, fl->fname, fl->vRefNum, fl->dirID, 0, 0, 1)) {
517 result = handleMessage(part_init(dfile), "text/plain",
518 0, (*mpack_prefs)->extract_text);
519 if (result != 0 || didchat <= 0) {
520 if (didchat < 0) {
521 chat("Decoding cancelled");
522 } else {
523 chat("Found nothing to decode");
524 }
525 }
526 fclose(dfile);
527 } else {
528 chat("Couldn't find source file");
529 }
530 ++fl;
531 }
532 fclose(tmpf);
533 HUnlock((Handle) dwin->hflist);
534 NAhiliteDItem(curstatwin->pwin, iOk, 0);
535 NAunlockWindow(curstatwin);
536 curstatwin = NULL;
537 SetCursor(&arrow);
538 DisposHandle((Handle) dwin->hflist);
539 }
540
541 /* return non-zero if two filenames have the same prefix
542 */
543 static int fprefixMatch(char *base, PCstr *match)
544 {
545 PCstr temp[257];
546 char *scan;
547 short prefixlen;
548
549 PtoPCstrcpy(temp, base);
550 scan = C(temp) + PCstrlen(temp) - 1;
551 while (isdigit(*scan) && scan > C(temp)) --scan;
552 prefixlen = scan - C(temp) + 1;
553 if (strncmp(C(temp), C(match), prefixlen)) return (0);
554 scan = C(match) + prefixlen;
555 while (isdigit(*scan)) ++scan;
556
557 return (!*scan);
558 }
559
560 /* do the add of a file to a list
561 */
562 static void addit(listwin *dw, short vRefNum, long dirID, char *fname)
563 {
564 long size = GetHandleSize((Handle) dw->hflist) / sizeof (filelist);
565 filelist *fl;
566 char *bp;
567 Cell c;
568 int i;
569 PCstr fbuf[42];
570
571 if (size == dw->count) {
572 SetHandleSize((Handle) dw->hflist, (++size * sizeof (filelist)));
573 if (MemError() != noErr) return;
574 }
575 MoveHHi((Handle) dw->hflist);
576 HLock((Handle) dw->hflist);
577 fl = *dw->hflist;
578 for (i = dw->count; i; --i, ++fl) {
579 if (fl->vRefNum == vRefNum && fl->dirID == dirID &&
580 *fl->fname == *fname && !strncmp(C(fl->fname), C(fname), *fl->fname)) {
581 break;
582 }
583 }
584 if (!i) {
585 fl->vRefNum = vRefNum;
586 fl->dirID = dirID;
587 PtoPCstrcpy(fl->fname, fname);
588 SetPt(&c, 0, dw->count);
589 LAddRow(1, ++dw->count, dw->l);
590 LSetCell((Ptr) C(fname), (short) Pstrlen(fname), c, dw->l);
591 }
592 HUnlock((Handle) dw->hflist);
593 }
594
595 /* add file set to file list
596 */
597 static void addfile(dw, fspec)
598 listwin *dw;
599 FSSpec *fspec;
600 {
601 CInfoPBRec cipbr;
602 HFileInfo *fpb = (HFileInfo *)&cipbr;
603 PCstr fbuf[42];
604 short idx, foundone = 0;
605 long procid;
606
607 /* remove working directory stuff */
608 if (fspec->parID == 0) {
609 GetWDInfo(fspec->vRefNum, &fspec->vRefNum, &fspec->parID, &procid);
610 }
611
612 /* loop through directory */
613 for (idx = 1; ; ++idx) {
614 fpb->ioVRefNum = fspec->vRefNum;
615 fpb->ioNamePtr = P(fbuf);
616 fpb->ioDirID = fspec->parID;
617 fpb->ioFDirIndex = idx;
618 if (PBGetCatInfoSync(&cipbr)) break;
619 SetClen(fbuf);
620
621 if (!(fpb->ioFlAttrib & 16) && fprefixMatch((char *)fspec->name, fbuf)) {
622 addit(dw, fspec->vRefNum, fspec->parID, (char *) P(fbuf));
623 foundone = 1;
624 }
625 }
626 if (!foundone) {
627 addit(dw, fspec->vRefNum, fspec->parID, (char *) fspec->name);
628 }
629 }
630
631 /* remove file from file list
632 */
633 static void removefile(dw)
634 listwin *dw;
635 {
636 filelist *fl;
637 int count;
638 Cell c;
639
640 c.h = c.v = 0;
641 if (LGetSelect(TRUE, &c, dw->l)) {
642 MoveHHi((Handle) dw->hflist);
643 HLock((Handle) dw->hflist);
644 fl = *dw->hflist + c.v;
645 count = dw->count - c.v;
646 while (--count) {
647 fl[0] = fl[1];
648 ++fl;
649 }
650 HUnlock((Handle) dw->hflist);
651 --dw->count;
652 LDelRow(1, c.v, dw->l);
653 }
654 }
655
656 /* close list window
657 */
658 static short listclose(win)
659 na_win *win;
660 {
661 LDispose(dwin->l);
662
663 return (alldone(win));
664 }
665
666 /* mouse procedure
667 */
668 static short listmouse(na_win *win, Point p, short type, short mods)
669 {
670 Cell c;
671
672 if (!(type & 1)) {
673 LClick(p, mods, dwin->l);
674 c.h = c.v = 0;
675 NAhiliteDItem((DialogPtr)win->pwin, iRemove, LGetSelect(TRUE, &c, dwin->l) ? 0 : 255);
676 }
677
678 return (NA_NOTPROCESSED);
679 }
680
681 /* control procedure
682 */
683 static short listctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
684 {
685 StandardFileReply reply;
686
687 switch (item) {
688 case iAdd:
689 NAgetFile(NULL, 1, textList, &reply);
690 if (reply.sfGood) {
691 if (!dwin->count) {
692 NAhiliteDItem((DialogPtr)win->pwin, iOk, 0);
693 }
694 addfile(dwin, &reply.sfFile);
695 }
696 return (NA_PROCESSED);
697
698 case iRemove:
699 removefile(dwin);
700 NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
701 if (!dwin->count) {
702 NAhiliteDItem((DialogPtr)win->pwin, iOk, 255);
703 }
704 return (NA_PROCESSED);
705
706 case iOk:
707 win->afterp = do_decodefiles;
708 case iCancel:
709 return (NA_REQCLOSE);
710 }
711
712 return (NA_NOTPROCESSED);
713 }
714
715 /* update the list window
716 */
717 static short listupdate(na_win *win, Boolean resize)
718 {
719 Rect r;
720
721 NAgetDRect(win->pwin, iFileList, &r);
722 FrameRect(&r);
723 LUpdate(win->pwin->visRgn, dwin->l);
724
725 return (NA_NOTPROCESSED);
726 }
727
728 /* initialize the list window
729 */
730 static short listinit(win, data)
731 na_win *win;
732 long *data;
733 {
734 FSSpec *fspec = (FSSpec *) data;
735 Rect r, zrect;
736 Point p;
737 Handle hand;
738 short type;
739
740 GetDItem((DialogPtr)win->pwin, iFileList, &type, &hand, &r);
741 InsetRect(&r, 1, 1);
742 zrect.top = zrect.bottom = zrect.left = p.h = p.v = 0;\
743 zrect.right = 1;
744 dwin->l = LNew(&r, &zrect, p, 0, win->pwin, 0, 0, 0, 1);
745 if (!dwin->l) return (NA_CLOSED);
746 (*dwin->l)->selFlags = lOnlyOne;
747 dwin->hflist = (filelist **) NewHandle(sizeof (filelist));
748 if (!dwin->hflist) {
749 LDispose(dwin->l);
750 return (NA_CLOSED);
751 }
752 dwin->count = 0;
753 addfile(dwin, fspec);
754 win->closep = listclose;
755 win->updatep = listupdate;
756 win->ctrlp = listctrl;
757 win->mousep = listmouse;
758 win->type = DECODELIST;
759 NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
760 ShowWindow(win->pwin);
761 LDoDraw(TRUE, dwin->l);
762
763 return (NA_NOTPROCESSED);
764 }
765
766 /* Decode procedure: first get a file, then open decode window
767 */
768 static void do_decode(FSSpec *fspec)
769 {
770 StandardFileReply infile;
771 na_win **wh, *wp;
772
773 if (!fspec) {
774 NAgetFile(NULL, 1, textList, &infile);
775 if (!infile.sfGood) return;
776 fspec = &infile.sfFile;
777 } else {
778 /* file supplied by drag & drop, look for existing decode window: */
779 for (wh = NAhead; wh && (*wh)->type != DECODELIST; wh = (*wh)->next);
780 if (wh && (wp = NAlockWindow(wh)) != NULL) {
781 addfile((listwin *) wp, fspec);
782 NAunlockWindow(wp);
783 return;
784 }
785 }
786 NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_DEFBUTTON |
787 NA_HASCONTROLS | NA_CLOSEBOX, NULL, decodeDLOG, (long *) fspec,
788 sizeof (listwin), listinit);
789 }
790
791 /* Map MIME type to/from Macintosh file types
792 */
793 void MapTypeCreator(char *contenttype, OSType type)
794 {
795 extern long _ftype, _fcreator;
796 PCstr tstr[257];
797 Handle h;
798 ICAttr attr;
799 long size = 0;
800 Ptr map;
801 ICMapEntry *ment;
802 unsigned char *scan, *end, *pstr;
803 short mapcount, i, foundit = 0;
804 OSType temp;
805
806 if (!type) CtoPCstrncpy(tstr, contenttype, 255);
807
808 /* first try a lookup via Internet Config */
809 if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
810 if (ICGetPref(icinst, kICMapping, &attr, nil, &size) == noErr
811 && size > 0 && (map = NewPtr(size)) != nil) {
812 if (ICGetPref(icinst, kICMapping, &attr, map, &size) == noErr) {
813 scan = (unsigned char *) map;
814 end = scan + size;
815 while (scan < end) {
816 ment = (ICMapEntry *) scan;
817 pstr = scan + ment->fixed_length;
818 scan += ment->total_length;
819 if (type && ment->file_type != type) continue;
820 pstr += *pstr + 1; /* skip over extension */
821 pstr += *pstr + 1; /* skip over creator app name */
822 pstr += *pstr + 1; /* skip over post app name */
823 if (type) {
824 PtoPCstrcpy((PCstr *) contenttype, (char *) pstr);
825 foundit = 1;
826 break;
827 } else if (EqualString(P(tstr), pstr, false, true)) {
828 _ftype = ment->file_type;
829 _fcreator = ment->file_creator;
830 foundit = 1;
831 break;
832 }
833 }
834 }
835 DisposPtr(map);
836 }
837 ICEnd(icinst);
838 }
839
840 /* if we didn't find it, try our quick&dirty mappings */
841 if (!foundit) {
842 if (type) {
843 mapcount = CountResources('TyCr');
844 for (i = 1; i <= mapcount; ++i) {
845 h = GetIndResource('TyCr', i);
846 if (h && **(OSType **)h == type) {
847 GetResInfo(h, &i, &temp, P(contenttype));
848 if (ResError() == noErr) break;
849 }
850 }
851 SetClen((PCstr *) contenttype);
852 } else {
853 h = GetNamedResource('TyCr', P(tstr));
854 if (h) {
855 _ftype = (*(OSType **)h)[0];
856 _fcreator = (*(OSType **)h)[1];
857 } else {
858 _ftype = '????';
859 _fcreator = 'mPAK';
860 }
861 }
862 }
863 }
864
865 /* get internet config string prefs
866 */
867 static short getICprefs(na_win *win, PCstr *eaddr, PCstr *smtphost)
868 {
869 char *scan, *end;
870 ICAttr attr;
871 long size;
872 ICError err = noErr;
873
874 *C(eaddr) = '\0';
875 SetPlen(eaddr);
876 *C(smtphost) = '\0';
877 SetPlen(smtphost);
878 if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
879 size = 256;
880 if (ICGetPref(icinst, kICEmail, &attr, (Ptr) eaddr, &size) == noErr
881 && win && (attr & ICattr_locked_mask)) {
882 NAenableDItem(win->pwin, iEmailAddr, 0);
883 }
884 SetClen(eaddr);
885 size = 256;
886 if (ICGetPref(icinst, kICSMTPHost, &attr, (Ptr) smtphost, &size) == noErr
887 && win && (attr & ICattr_locked_mask)) {
888 NAenableDItem(win->pwin, iMailServer, 0);
889 }
890 SetClen(smtphost);
891 ICEnd(icinst);
892 } else {
893 HLock((Handle) mpack_prefs);
894 end = (char *) (*mpack_prefs) + GetHandleSize((Handle) mpack_prefs);
895 scan = (*mpack_prefs)->internet_host;
896 while (scan < end && *scan++);
897 if (scan < end) CtoPCstrcpy(eaddr, scan);
898 while (scan < end && *scan++);
899 if (scan < end) CtoPCstrcpy(smtphost, scan);
900 HUnlock((Handle) mpack_prefs);
901 }
902 }
903
904 /* copy desc file, with word-wrap
905 */
906 static short copydesc(FILE *out, TEHandle hTE)
907 {
908 char c;
909 short i, count, word, col, reset;
910 char **htxt;
911
912 count = (*hTE)->teLength;
913 htxt = (char **) (*hTE)->hText;
914 for (i = word = col = 0; i < count; ++i) {
915 c = (*htxt)[i];
916 reset = i - word == 80 || c == '\r';
917 if (reset || c == ' ') {
918 while (word < i) putc((*htxt)[word], out), ++word;
919 }
920 if (reset || ++col == 80) {
921 putc('\r', out);
922 c = (*htxt)[word];
923 if (c == ' ' || c == '\r') ++word;
924 col = 0;
925 }
926 }
927 while (word < i) putc((*htxt)[word], out), ++word;
928 rewind(out);
929 }
930
931 /* start up MacTCP callback
932 */
933 static void mytcpinit(short status)
934 {
935 static DialogPtr dialog = NULL;
936 GrafPtr save;
937 Rect box;
938
939 if (status < 0) {
940 tcpstart = -1;
941 } else if (status == 0) {
942 tcpstart = 1;
943 } else {
944 if (!dialog && status < 100) {
945 dialog = GetNewDialog(progDLOG, nil, (WindowPtr) -1);
946 NAsetIText(dialog, iWorkText, "\pWaiting for MacTCP to finish. Press \021. to stop.");
947 }
948 if (dialog) {
949 GetPort(&save);
950 SetPort(dialog);
951 NAgetDRect(dialog, iProgress, &box);
952 FrameRect(&box);
953 InsetRect(&box, 1, 1);
954 box.right = box.left + (box.right - box.left) * status / 100;
955 FillRect(&box, qd.dkGray);
956 SetPort(save);
957 if (status == 100) {
958 DisposDialog(dialog);
959 dialog = NULL;
960 }
961 }
962 }
963 }
964
965 /* update the progress bar
966 */
967 static short progressupdate(na_win *win, Boolean newsize)
968 {
969 Rect box;
970
971 if (prwin->percent >= 0) {
972 NAgetDRect(win->pwin, iProgress, &box);
973 FrameRect(&box);
974 InsetRect(&box, 1, 1);
975 if (prwin->percent) {
976 box.right = box.left + (box.right - box.left) * prwin->percent / 100;
977 FillRect(&box, qd.dkGray);
978 } else {
979 EraseRect(&box);
980 }
981 }
982
983 return (NA_NOTPROCESSED);
984 }
985
986 /* handle the cancel button
987 */
988 static short progressctrl(na_win *win, Point p, short item, short mods,
989 ControlHandle ctrlh)
990 {
991 return (item == iCancel ? NA_REQCLOSE : NA_NOTPROCESSED);
992 }
993
994 /* close progress window
995 */
996 static short progressclose(na_win *win)
997 {
998 NAmodalMenus(0);
999
1000 return (NA_CLOSED);
1001 }
1002
1003 /* make/go directory under prefs and return directory number
1004 */
1005 static OSErr prefsubdir(PCstr *name, long *dirID)
1006 {
1007 CInfoPBRec cipbr;
1008 DirInfo *dpb = &cipbr.dirInfo;
1009 long subdir, dir;
1010 short vref = pfolder->fspec.vRefNum;
1011 OSErr err;
1012
1013 err = DirCreate(vref, dir = pfolder->fspec.parID, P(name), &subdir);
1014 if (err == dupFNErr) {
1015 dpb->ioVRefNum = vref;
1016 dpb->ioNamePtr = P(name);
1017 dpb->ioDrDirID = dir;
1018 dpb->ioFDirIndex = 0;
1019 if ((err = PBGetCatInfoSync(&cipbr)) != noErr) return (err);
1020 subdir = dpb->ioDrDirID;
1021 } else if (err != noErr) {
1022 return (err);
1023 }
1024 *dirID = subdir;
1025
1026 return (noErr);
1027 }
1028
1029 /* smtp status task
1030 */
1031 static void smtpstat(void *wh, short code, short err, long num, char *errstr)
1032 {
1033 na_win *win, **winh;
1034 char msg[256];
1035 OSErr oserr = noErr;
1036
1037 /* verify win is valid */
1038 for (winh = NAhead; winh && winh != wh; winh = (*winh)->next);
1039 if (!winh) return;
1040
1041 /* handle SMTP callback */
1042 win = NAlockWindow((na_win **) wh);
1043 if (code == NASMTP_progress) {
1044 prwin->percent = err;
1045 progressupdate(win, false);
1046 } else if (code == NASMTP_badaddr) {
1047 sprintf(msg, "Invalid address: <%s>. Email will be sent to valid recipients.",
1048 errstr);
1049 yell(msg);
1050 } else {
1051 switch (code) {
1052 case NASMTP_nomem:
1053 yell("Not enough memory to send email");
1054 break;
1055 case NASMTP_tcpfail:
1056 yell("Failed to connect to mail host");
1057 break;
1058 case NASMTP_temperr:
1059 case NASMTP_permerr:
1060 sprintf(msg, "Delivery failed: %s", errstr);
1061 yell(msg);
1062 break;
1063 default:
1064 yell("Mail delivery failed.");
1065 case NASMTP_completed:
1066 break;
1067 }
1068 mwin->sending = false;
1069 oserr = HDelete(mwin->fspec.vRefNum, mwin->fspec.parID, mwin->fspec.name);
1070 }
1071 if (oserr != noErr && oserr != fnfErr) {
1072 if (mwin->remaining) ++mwin->cpb.hFileInfo.ioFDirIndex;
1073 yell("Unable to remove temporary email file.");
1074 }
1075 NAunlockWindowh((na_win **) wh, win);
1076 }
1077
1078 /* Get the email hostname
1079 */
1080 static void mailhost(void *user, na_tcp s, short status, long size, char *data)
1081 {
1082 struct mpack_preferences *mp;
1083 char *ihost;
1084 na_win *win, **winh;
1085 long len, oldsize;
1086
1087 /* first make sure our window still exists */
1088 for (winh = NAhead; winh && winh != user; winh = (*winh)->next);
1089 if (!winh) return;
1090 win = NAlockWindow(winh);
1091
1092 /* check for errors */
1093 if (status != NATCP_connect) {
1094 warn("Failed to get hostname from MacTCP");
1095 } else {
1096 mwin->gothost = true;
1097 if (data[size - 1] == '.') --size;
1098
1099 /* update internet_host preference */
1100 len = strlen((*mpack_prefs)->internet_host);
1101 oldsize = GetHandleSize((Handle) mpack_prefs);
1102 if (len < size) {
1103 SetHandleSize((Handle) mpack_prefs, oldsize + (size - len));
1104 if (MemError() != noErr) return;
1105 }
1106 HLock((Handle) mpack_prefs);
1107 mp = *mpack_prefs;
1108 ihost = mp->internet_host;
1109 memmove(ihost + size + 1, ihost + len + 1,
1110 oldsize - len - 1 - ((char *) ihost - (char *) mp));
1111 memcpy(ihost, data, size);
1112 ihost[size] = '\0';
1113 HUnlock((Handle) mpack_prefs);
1114 }
1115 NAunlockWindowh(winh, win);
1116 }
1117
1118 /* clean up mail task
1119 */
1120 static short mailclose(na_win *win)
1121 {
1122 if (mwin->dfile != NULL) fclose(mwin->dfile);
1123 if (mwin->envelope) DisposeHandle(mwin->envelope);
1124 if (mwin->headers) DisposeHandle(mwin->headers);
1125 NAmodalMenus(0);
1126
1127 return (alldone(win));
1128 }
1129
1130 /* send email
1131 */
1132 static short mailtask(na_win *win)
1133 {
1134 short vrefnum, encoding, refnum, result;
1135 long procid;
1136 FILE *tmpf, *fp, *resfork;
1137 OSErr err;
1138 CInfoPBRec cipbr;
1139 HFileInfo *fpb = (HFileInfo *)&cipbr;
1140 PCstr tstr[257], mtype[257], fname[257];
1141 extern long _ftype, _fcreator;
1142
1143 switch (mwin->state) {
1144 case MS_MACTCP:
1145 if (tcpstart < 0) {
1146 yell("Couldn't find MacTCP");
1147 return (NA_REQCLOSE);
1148 }
1149 if (tcpstart == 0) break;
1150 ++mwin->state;
1151 NAsetIText(win->pwin, iWorkText, "\pGetting Hostname");
1152 mwin->gothost = false;
1153 NATCPgethost(mailhost, (void *) GetWRefCon(win->pwin));
1154 /* fall through */
1155 case MS_GETHOST:
1156 if (!mwin->gothost) break;
1157 ++mwin->state;
1158 /* fall through */
1159 case MS_ENCODE:
1160 NAsetIText(win->pwin, iWorkText, "\pEncoding file");
1161
1162 /* get temp output filename for email */
1163 if (mwin->useemail) {
1164 mwin->ofile.vRefNum = pfolder->fspec.vRefNum;
1165 memcpy(mwin->ofile.name, "\pemail", 6);
1166 if (prefsubdir("\poutgoing-email", &mwin->ofile.parID) != noErr) {
1167 yell("Failed to write encoded file");
1168 return (NA_REQCLOSE);
1169 }
1170 }
1171
1172 /* set file type */
1173 SetCursor(&watch);
1174 MapTypeCreator((char *) mtype, mwin->ftype);
1175
1176 /* Determine the correct encoding */
1177 encoding = (*mpack_prefs)->encoding;
1178 fpb->ioVRefNum = mwin->fspec.vRefNum;
1179 fpb->ioNamePtr = mwin->fspec.name;
1180 fpb->ioDirID = mwin->fspec.parID;
1181 fpb->ioFDirIndex = 0;
1182 if (PBGetCatInfoSync(&cipbr) != noErr) {
1183 SetCursor(&arrow);
1184 yell("File disappeared before being encoded!");
1185 return (NA_REQCLOSE);
1186 }
1187 if (encoding == EN_AUTO) {
1188 encoding = EN_DOUBLE;
1189 if (!fpb->ioFlRLgLen && *mtype != '\0') encoding = EN_DATA;
1190 }
1191 if (!fpb->ioFlLgLen) encoding = EN_SINGLE;
1192
1193 /* do applesingle/appledouble encoding */
1194 tmpf = tmpfile();
1195 fp = Macopen(tmpf, mwin->fspec.name, mwin->fspec.vRefNum, mwin->fspec.parID,
1196 strcmp(C(mtype), "text/plain") ? 1 : 0, 0, fsRdPerm);
1197 if (!fp) {
1198 fclose(tmpf);
1199 SetCursor(&arrow);
1200 yell("Couldn't save encoded file");
1201 return (NA_REQCLOSE);
1202 }
1203 if (encoding == EN_DATA) {
1204 fclose(tmpf);
1205 tmpf = NULL;
1206 } else {
1207 /* open resource fork & output file for applesingle/double encoding */
1208 resfork = Macopen(tmpf, mwin->fspec.name, mwin->fspec.vRefNum,
1209 mwin->fspec.parID, 1, 1, 1);
1210 if (encode_applefile(tmpf, fpb, resfork, encoding == EN_SINGLE ? fp : NULL) < 0) {
1211 SetCursor(&arrow);
1212 yell("Couldn't save encoded file");
1213 return (NA_REQCLOSE);
1214 }
1215 rewind(tmpf);
1216 if (encoding == EN_SINGLE) {
1217 fp = tmpf;
1218 tmpf = NULL;
1219 strcpy(C(mtype), "application/applefile");
1220 SetPlen(mtype);
1221 }
1222 }
1223
1224 /* generate output files */
1225 _fcreator = 'mPAK';
1226 _ftype = 'TEXT';
1227 GetVol(0, &vrefnum);
1228 err = OpenWD(mwin->ofile.vRefNum, mwin->ofile.parID, 0, &refnum);
1229 SetVol(0, err == noErr ? refnum : mwin->ofile.vRefNum);
1230 PtoPCstrcpy(tstr, (char *) mwin->ofile.name);
1231 PtoPCstrcpy(fname, (char *) mwin->fspec.name);
1232 result = encode(fp, tmpf, C(fname), mwin->dfile, C(mwin->subj), NULL,
1233 mwin->partsize, PCstrlen(mtype) ? C(mtype) : NULL, C(tstr));
1234 if (err == noErr) CloseWD(refnum);
1235 SetVol(0, vrefnum);
1236 if (tmpf) fclose(tmpf);
1237 fclose(fp);
1238 if (mwin->dfile) {
1239 fclose(mwin->dfile);
1240 mwin->dfile = NULL;
1241 }
1242 SetCursor(&arrow);
1243 if (!mwin->useemail) return (NA_REQCLOSE);
1244 prwin->percent = 0;
1245 progressupdate(win, false);
1246 ++mwin->state;
1247
1248 /* count files */
1249 mwin->cpb.dirInfo.ioVRefNum = mwin->ofile.vRefNum;
1250 mwin->cpb.dirInfo.ioDrDirID = mwin->dirID = mwin->ofile.parID;
1251 mwin->cpb.dirInfo.ioFDirIndex = -1;
1252 if (PBGetCatInfoSync(&mwin->cpb) != noErr) {
1253 return (NA_CLOSED);
1254 }
1255 mwin->remaining = mwin->cpb.dirInfo.ioDrNmFls;
1256 mwin->cpb.dirInfo.ioFDirIndex = 1;
1257 /* fall through */
1258 case MS_SENDING:
1259 if (mwin->sending) break;
1260 if (!mwin->remaining) return (NA_REQCLOSE);
1261 sprintf(C(tstr), "Email parts remaining to submit: %d", mwin->remaining--);
1262 SetPlen(tstr);
1263 NAsetIText(win->pwin, iWorkText, tstr);
1264 prwin->percent = 0;
1265 progressupdate(win, false);
1266 mwin->cpb.hFileInfo.ioDirID = mwin->dirID;
1267 mwin->cpb.hFileInfo.ioNamePtr = (StringPtr) &mwin->fspec.name;
1268 if (PBGetCatInfoSync(&mwin->cpb) != noErr) {
1269 yell("Email disappeared before submission!");
1270 return (NA_REQCLOSE);
1271 }
1272 mwin->sending = true;
1273 mwin->fspec.vRefNum = mwin->cpb.hFileInfo.ioVRefNum;
1274 mwin->fspec.parID = mwin->dirID;
1275 NASMTPsubmit(smtpstat, C(mwin->server), &mwin->fspec,
1276 mwin->headers, mwin->envelope,
1277 NASMTP_crtrans, (void *) GetWRefCon(win->pwin));
1278 break;
1279 }
1280
1281 return (NA_NOTPROCESSED);
1282 }
1283
1284 /* Following routine stolen from Mark Crispin's c-client library:
1285 *
1286 * Write current time in RFC 822 format
1287 * Accepts: destination string
1288 *
1289 * This depends upon the ReadLocation() call in System 7 and the
1290 * user properly setting his location/timezone in the Map control
1291 * panel.
1292 * 2/95 - I added support for dlsDelta & compatibility checking
1293 */
1294 void rfc822_date(char *string)
1295 {
1296 long tz, tzm;
1297 time_t ti = time (0);
1298 struct tm *t = localtime (&ti);
1299 MachineLocation loc;
1300
1301 /* output date */
1302 strcpy(string, "Date: ");
1303 string += 6;
1304 strftime (string,1024,"%a, %d %b %Y %H:%M:%S ",t);
1305 /* now output time zone, if we can get it */
1306 tz = 0;
1307 if (Gestalt(gestaltScriptMgrVersion, &tz) == noErr && tz >= 200) {
1308 ReadLocation(&loc); /* get location/timezone */
1309 /* get sign-extended time zone */
1310 tz = (loc.gmtFlags.gmtDelta & 0x00ffffff) |
1311 ((loc.gmtFlags.gmtDelta & 0x00800000) ? 0xff000000 : 0);
1312 tz /= 60; /* get timezone in minutes */
1313 tzm = tz % 60; /* get minutes from the hour */
1314 sprintf (string += strlen(string),"%+03ld%02ld",
1315 tz/60,tzm >= 0 ? tzm : -tzm);
1316 if (!tzm && tz <= -240 && tz >= -660) {
1317 string += strlen(string);
1318 if (loc.gmtFlags.dlsDelta & 0x80) {
1319 sprintf(string, " (%cDT)", "AECMPYHB"[- (tz / 60) - 3]);
1320 } else {
1321 sprintf(string, " (%cST)", "AECMPYHB"[- (tz / 60) - 4]);
1322 }
1323 }
1324 } else {
1325 sprintf(string + strlen(string), "+0000 (Local Time Zone Unknown)");
1326 }
1327 }
1328
1329 /* init mail sending
1330 */
1331 static short mailinit(na_win *win, long *data)
1332 {
1333 encodewin *ew = (encodewin *) data;
1334 WindowPtr pwin = ew->w.winp.pwin;
1335 ControlHandle ctrlh;
1336 PCstr tstr[257], email[257];
1337
1338 /* copy values from encode window */
1339 NAgetIText(pwin, iSubj, mwin->subj);
1340 NAgetIText(pwin, iEmailto, email);
1341 mwin->partsize = ew->partsize;
1342 mwin->useemail = ew->useemail;
1343 mwin->fspec = ew->fspec;
1344 mwin->ftype = ew->ftype;
1345 mwin->ofile = ew->ofile;
1346
1347 /* copy desc file */
1348 mwin->dfile = NULL;
1349 if ((*ew->w.hTE)->teLength && (mwin->dfile = tmpfile()) != NULL) {
1350 copydesc(mwin->dfile, ew->w.hTE);
1351 }
1352
1353 /* set procedures */
1354 win->taskp = mailtask;
1355 win->updatep = progressupdate;
1356 win->ctrlp = progressctrl;
1357 win->closep = mailclose;
1358
1359 /* Customize Progress window, set up envelope & headers for email */
1360 prwin->percent = -1;
1361 NAgetDHandle(win->pwin, iCancel, &ctrlh);
1362 SetCTitle(ctrlh, "\pStop");
1363 NAmodalMenus(1);
1364 if (!mwin->useemail) {
1365 mwin->state = MS_ENCODE;
1366 } else {
1367 if (!tcpstart) NATCPinit(mytcpinit);
1368 NAsetIText(win->pwin, iWorkText, "\pLooking for MacTCP");
1369 mwin->state = MS_MACTCP;
1370
1371 /* create envelope, get server */
1372 getICprefs(NULL, tstr, mwin->server);
1373 if (PtrToHand(C(tstr), &mwin->envelope, PCstrlen(tstr) + 1) != noErr
1374 || PtrAndHand(C(email), mwin->envelope, PCstrlen(email) + 1) != noErr) {
1375 if (mwin->envelope) DisposeHandle(mwin->envelope);
1376 return (NA_CLOSED);
1377 }
1378
1379 /* create headers */
1380 if ((mwin->headers = NewHandle(1024)) == NULL) {
1381 DisposeHandle(mwin->envelope);
1382 return (NA_CLOSED);
1383 }
1384 HLock(mwin->headers);
1385 rfc822_date((char *) *mwin->headers);
1386 sprintf((char *) (*mwin->headers) + strlen((char *) (*mwin->headers)),
1387 "\r\nFrom: %s\r\nTo: %s\r\n", C(tstr), C(email));
1388 HUnlock(mwin->headers);
1389 SetHandleSize(mwin->headers, strlen((char *) (*mwin->headers)));
1390 }
1391
1392 return (NA_NOTPROCESSED);
1393 }
1394
1395 /* update the encode window
1396 */
1397 static short encodeupdate(na_win *win, Boolean newsize)
1398 {
1399 Rect btmp;
1400 ControlHandle ctrlh;
1401
1402 /* draw double-line */
1403 NAgetDRect(win->pwin, iBar, &btmp);
1404 FrameRect(&btmp);
1405
1406 /* draw disabled edittext boxes */
1407 NAgetDHandle(win->pwin, iLimit, &ctrlh);
1408 if (!GetCtlValue(ctrlh)) {
1409 NAhiliteDItem(win->pwin, iPartLimit, 255);
1410 }
1411 if (NAradioGet(win->pwin, iEmail, iSavefile) == iSavefile) {
1412 NAhiliteDItem(win->pwin, iEmailto, 255);
1413 }
1414
1415 return (NATEupdatep(win, newsize));
1416 }
1417
1418 /* select desc text
1419 */
1420 static short seldesctext(na_win *win)
1421 {
1422 win->activep = NATEactivep;
1423 win->idlep = NATEidlep;
1424 NATEactivep(win, true);
1425 ewin->nateon = true;
1426 SelIText(win->pwin, iDescEdit, 0, 0);
1427 TESetSelect(32767, 32767, twin->hTE);
1428 }
1429
1430 /* encode control proc
1431 */
1432 static short encodectrl(na_win *win, Point p, short item,
1433 short mods, ControlHandle ctrlh)
1434 {
1435 short value;
1436 DialogPeek dpeek = (DialogPeek) win->pwin;
1437 char *scan;
1438 Boolean good;
1439 StandardFileReply reply;
1440 PCstr tstr[257];
1441
1442 if (ctrlh == twin->vctrl) {
1443 return (NATEctrlp(win, p, item, mods, ctrlh));
1444 }
1445 switch (item) {
1446 case iOk:
1447 /* get part size */
1448 ewin->partsize = 0;
1449 NAgetDHandle(win->pwin, iLimit, &ctrlh);
1450 if (GetCtlValue(ctrlh)) {
1451 NAgetIText(win->pwin, iPartLimit, tstr);
1452 ewin->partsize = atol(C(tstr)) * 1000;
1453 }
1454 NAgetIText(win->pwin, iEmailto, tstr);
1455 ewin->useemail = NAradioGet(win->pwin, iEmail, iSavefile) == iEmail;
1456 if (ewin->useemail) {
1457 /* verify email address */
1458 if (!strchr(C(tstr), '@')) {
1459 yell("Invalid Email address, please re-enter");
1460 SelIText(win->pwin, iEmailto, 0, 32767);
1461 break;
1462 }
1463 } else {
1464 /* get output filename */
1465 PtoPCstrcpy(tstr, (char *) ewin->fspec.name);
1466 if (PCstrlen(tstr) > 23) {
1467 PCstrlen(tstr) = 23;
1468 SetClen(tstr);
1469 }
1470 strcat(C(tstr), ".mime");
1471 SetPlen(tstr);
1472 do {
1473 NAputFile(ewin->partsize ? "\pPart prefix" : "\pEmail file:",
1474 tstr, &reply);
1475 good = true;
1476 if (reply.sfGood
1477 && EqualString(reply.sfFile.name,
1478 ewin->fspec.name, true, false)) {
1479 good = false;
1480 yell("The output filename must be different from the input filename");
1481 }
1482 } while (!good);
1483 if (!reply.sfGood) break;
1484 ewin->ofile = reply.sfFile;
1485 }
1486 if (NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_HASTASK
1487 | NA_USERESOURCE | NA_MODAL, NULL, progDLOG,
1488 (long *) win, sizeof (mailwin), mailinit) == NA_CLOSED) {
1489 warn("Not enough memory to proceed");
1490 break;
1491 }
1492 case iCancel:
1493 return (NA_REQCLOSE);
1494 case iEmail:
1495 case iSavefile:
1496 NAradioSet(win->pwin, iEmail, iSavefile, item);
1497 NAenableDItem(win->pwin, iEmailto, item == iEmail ? 1 : 0);
1498 NAhiliteDItem(win->pwin, iEmailto, item == iEmail ? 0 : 255);
1499 if (item == iEmail || dpeek->editField == iEmailto - 1) {
1500 SelIText(win->pwin, item == iEmail ? iEmailto : iSubj, 0, 32767);
1501 }
1502 break;
1503 case iLimit:
1504 SetCtlValue(ctrlh, value = !GetCtlValue(ctrlh));
1505 NAenableDItem(win->pwin, iPartLimit, value ? 1 : 0);
1506 NAhiliteDItem(win->pwin, iPartLimit, value ? 0 : 255);
1507 if (value || dpeek->editField == iPartLimit - 1) {
1508 SelIText(win->pwin, value ? iPartLimit : iSubj, 0, 32767);
1509 }
1510 break;
1511 case iDescEdit:
1512 case iSubj:
1513 case iEmailto:
1514 case iPartLimit:
1515 if (!ewin->nateon && dpeek->editField == iDescEdit - 1) {
1516 seldesctext(win);
1517 }
1518 break;
1519 }
1520 if (ewin->nateon && dpeek->editField != iDescEdit - 1) {
1521 win->activep = NULL;
1522 win->idlep = NULL;
1523 NATEactivep(win, false);
1524 ewin->nateon = false;
1525 }
1526
1527 return (NA_NOTPROCESSED);
1528 }
1529
1530 /* encode key proc
1531 */
1532 static short encodekey(na_win *win, long c, short mods)
1533 {
1534 if (!(mods & cmdKey)) {
1535 if (ewin->nateon && c != '\t' && c != '\n' && c != '\3' && c != '\033') {
1536 return (NATEkeyp(win, c, mods));
1537 }
1538 }
1539
1540 return (NA_NOTPROCESSED);
1541 }
1542
1543 /* menu proc for encode window
1544 */
1545 static short encodemenu(na_win *win, WORD menu, WORD item)
1546 {
1547 StandardFileReply descfile;
1548 MenuHandle mf = NAmenuh(mFile);
1549 short result = NA_NOTPROCESSED;
1550 short refnum;
1551 long size;
1552 Ptr text;
1553 Boolean success;
1554
1555 switch (menu) {
1556 case 0:
1557 EnableItem(mf, iInsert);
1558 /* fall through */
1559 case mEdit:
1560 result = ewin->nateon ? NATEmenup(win, menu, item)
1561 : NAdialogMenu(win, menu, item);
1562 break;
1563 case mFile:
1564 if (item != iInsert) break;
1565 result = NA_PROCESSED;
1566 NAgetFile(NULL, 1, textList, &descfile);
1567 if (!descfile.sfGood) break;
1568 if (HOpen(descfile.sfFile.vRefNum, descfile.sfFile.parID,
1569 descfile.sfFile.name, fsRdPerm, &refnum) != noErr) {
1570 warn("Failed to open file");
1571 break;
1572 }
1573 text = NULL;
1574 success = GetEOF(refnum, &size) == noErr && (text = NewPtr(size)) != NULL
1575 && FSRead(refnum, &size, text) == noErr;
1576 if (success) {
1577 TEInsert(text, size, twin->hTE);
1578 TESelView(twin->hTE);
1579 NATEsetscroll(win, false, (Rect*) NULL, (Rect*) NULL);
1580 } else {
1581 warn("Failed to read file");
1582 }
1583 if (text) DisposPtr(text);
1584 FSClose(refnum);
1585 break;
1586 }
1587 if (menu != 0) DisableItem(mf, iInsert);
1588
1589 return (result);
1590 }
1591
1592 /* mouse proc for encode window
1593 */
1594 static short encodemouse(na_win *win, Point p, short type, short mods)
1595 {
1596 if (p.v >= twin->topoff && !ewin->nateon) seldesctext(win);
1597
1598 return (NATEmousep(win, p, type, mods));
1599 }
1600
1601 /* close the encode window
1602 */
1603 static short encodeclose(na_win *win)
1604 {
1605 NATEclosep(win);
1606
1607 return (NA_CLOSED);
1608 }
1609
1610 /* init the encode window
1611 */
1612 static short encodeinit(na_win *win, long *data)
1613 {
1614 StandardFileReply *sf = (StandardFileReply *) data;
1615 Rect rtmp, btmp;
1616 FontInfo finfo;
1617
1618 /* copy data */
1619 ewin->fspec = sf->sfFile;
1620 ewin->ftype = sf->sfType;
1621
1622 /* set sizing limits */
1623 NAgetDRect(win->pwin, iBar, &btmp);
1624 rtmp = win->pwin->portRect;
1625 win->minw = win->maxw = rtmp.right - rtmp.left;
1626 win->minh = btmp.bottom + 64;
1627 twin->topoff = btmp.bottom;
1628
1629 /* init text area */
1630 TextFont(monaco);
1631 TextSize(9);
1632 GetFontInfo(&finfo);
1633 NATEinit(win, NATE_NOHSCROLL, 80 * finfo.widMax + 2, NULL, 0);
1634 ewin->nateon = 0;
1635 TextFont(0);
1636 TextSize(0);
1637
1638 /* set control values */
1639 NAradioSet(win->pwin, iEmail, iSavefile, iSavefile);
1640 if (tcpstart < 0) NAhiliteDItem(win->pwin, iEmail, 255);
1641 NAenableDItem(win->pwin, iEmailto, 0);
1642 NAenableDItem(win->pwin, iPartLimit, 0);
1643 NAsetIText(win->pwin, iSubj, ewin->fspec.name);
1644 SelIText(win->pwin, iSubj, 0, 32767);
1645 SetWTitle(win->pwin, ewin->fspec.name);
1646 ShowWindow(win->pwin);
1647
1648 /* set window procedures */
1649 win->updatep = encodeupdate;
1650 win->closep = encodeclose;
1651 win->keyp = encodekey;
1652 win->ctrlp = encodectrl;
1653 win->mousep = encodemouse;
1654 win->menup = encodemenu;
1655 win->idlep = NULL;
1656 win->activep = NULL;
1657
1658 return (NA_NOTPROCESSED);
1659 }
1660
1661 /* Encode procedure: first get a file, then open encode save window
1662 */
1663 static void do_encode(FSSpec *fspec, OSType ftype)
1664 {
1665 StandardFileReply infile;
1666
1667 if (!fspec) {
1668 NAgetFile(NULL, -1, NULL, &infile);
1669 if (!infile.sfGood) return;
1670 } else {
1671 infile.sfFile = *fspec;
1672 infile.sfType = ftype;
1673 }
1674 NAwindow(NULL, NA_DIALOGWINDOW | NA_TITLEBAR | NA_GROWBOX | NA_USERESOURCE
1675 | NA_DEFBUTTON | NA_HASCONTROLS,
1676 NULL, sendDLOG, (long *) &infile, sizeof (encodewin), encodeinit);
1677 }
1678
1679 /* Open a file via drag&drop
1680 */
1681 static short openfile(short message, FSSpec *fspec, FInfo *finfo)
1682 {
1683 if (message != appOpen) return (-1);
1684
1685 /* open file */
1686 if (finfo->fdType == 'TEXT') {
1687 do_decode(fspec);
1688 } else {
1689 do_encode(fspec, finfo->fdType);
1690 }
1691
1692 return (0);
1693 }
1694
1695 #define hwinfo ((nate_win *)win)
1696
1697 /* help close procedure
1698 */
1699 static short helpclose(na_win *win)
1700 {
1701 helpw = NULL;
1702
1703 return (NATEclosep(win));
1704 }
1705
1706 /* help window procedure
1707 */
1708 static short helpwindow(na_win *win, long *data)
1709 {
1710 Rect rtemp, vtemp;
1711 Handle h, hs;
1712 long len;
1713 TEHandle hTE;
1714
1715 rtemp = win->pwin->portRect;
1716 vtemp = rtemp;
1717 vtemp.right = vtemp.left + (hwinfo->docwidth = 475);
1718 win->mousep = NATEmousep;
1719 win->idlep = NATEidlep;
1720 win->menup = NATEmenup;
1721 win->activep = NATEactivep;
1722 win->updatep = NATEupdatep;
1723 win->ctrlp = NATEctrlp;
1724 win->closep = helpclose;
1725 win->cursorRgn = NewRgn();
1726 hwinfo->vctrl = hwinfo->hctrl = NULL;
1727
1728 TEAutoView(true, hTE = hwinfo->hTE = TEStylNew(&vtemp, &rtemp));
1729 h = GetResource('TEXT', helpTEXT);
1730 hs = GetResource('styl', helpSTYL);
1731 len = GetHandleSize(h);
1732 HLock(h);
1733 TEStylInsert(*h, len, (StScrpHandle) hs, hTE);
1734 HUnlock(h);
1735 TESetSelect(0, 0, hTE);
1736 hwinfo->lheight = TEGetHeight((*hTE)->nLines, 0, hTE) / (*hTE)->nLines;
1737 ShowWindow(helpw = win->pwin);
1738
1739 return (NA_NOTPROCESSED);
1740 }
1741
1742 /* Set the hostname: TCP callback
1743 */
1744 static void sethost(void *user, na_tcp s, short status, long size, char *data)
1745 {
1746 PCstr host[65];
1747 Rect box;
1748 na_win *win, **winh;
1749
1750 /* first make sure our window still exists */
1751 for (winh = NAhead; winh && (*winh)->type != PREFWIN; winh = (*winh)->next);
1752 if (!winh || (*winh)->child != user) return;
1753 win = NAlockWindow((na_win **) user);
1754
1755 /* check for errors */
1756 if (status != NATCP_connect) {
1757 warn("Failed to get hostname from MacTCP");
1758 } else {
1759 if (data[size - 1] == '.') --size;
1760 PCstrlen(host) = size;
1761 memcpy(C(host), data, size);
1762 NAsetIText((*winh)->pwin, iHost, host);
1763 SelIText((*winh)->pwin, iHost, 0, 32767);
1764 }
1765 prwin->percent = 100;
1766 progressupdate(win, false);
1767 NAunlockWindowh(winh, win);
1768 }
1769
1770 /* if TCP is active, get hostname
1771 */
1772 static short settask(na_win *win)
1773 {
1774 if (tcpstart == 0 && !prwin->percent) {
1775 NAsetIText(win->pwin, iWorkText, "\pLooking for MacTCP");
1776 prwin->percent = 1;
1777 progressupdate(win, false);
1778 NATCPinit(mytcpinit);
1779 } else if (tcpstart == 1 && prwin->percent < 50) {
1780 NAsetIText(win->pwin, iWorkText, "\pLooking up Internet hostname");
1781 prwin->percent = 50;
1782 progressupdate(win, false);
1783 NATCPgethost(sethost, (void *) GetWRefCon(win->pwin));
1784 }
1785 progressupdate(win, false);
1786 if (tcpstart == -1) {
1787 warn("MacTCP not available");
1788 NAhiliteDItem((*win->parent)->pwin, iSet, 255);
1789 }
1790
1791 return (tcpstart == -1 || prwin->percent == 100 ? NA_CLOSED : NA_NOTPROCESSED);
1792 }
1793
1794 /* set the Internet host via MacTCP
1795 */
1796 static short setinit(na_win *win, long *data)
1797 {
1798 win->taskp = settask;
1799 win->updatep = progressupdate;
1800 win->closep = progressclose;
1801 NAmodalMenus(1);
1802
1803 return (NA_NOTPROCESSED);
1804 }
1805
1806 /* preference control procedure
1807 */
1808 static short prefsctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
1809 {
1810 PCstr tmpstr[257];
1811 short encoding, extract_text, quit_finished, result = NA_NOTPROCESSED;
1812 ControlHandle ctrl;
1813 char *scan, *end;
1814 short changed, len, i, useic;
1815 static short prefitem[3] = { iHost, iEmailAddr, iMailServer };
1816
1817 switch (item) {
1818 case iOk:
1819 HLock((Handle) mpack_prefs);
1820 changed = 0;
1821 encoding = NAradioGet(win->pwin, iAuto, iDouble) - iAuto;
1822 NAgetDHandle(win->pwin, iTextEncode, &ctrl);
1823 extract_text = GetCtlValue(ctrl);
1824 NAgetDHandle(win->pwin, iQuitFinish, &ctrl);
1825 quit_finished = GetCtlValue(ctrl);
1826 if (encoding != (*mpack_prefs)->encoding
1827 || extract_text != (*mpack_prefs)->extract_text
1828 || quit_finished != (*mpack_prefs)->quit_finished) {
1829 changed = 1;
1830 }
1831 if (changed) {
1832 (*mpack_prefs)->encoding = encoding;
1833 (*mpack_prefs)->extract_text = extract_text;
1834 (*mpack_prefs)->quit_finished = quit_finished;
1835 ChangedResource((Handle) mpack_prefs);
1836 changed = 0;
1837 }
1838 len = 1;
1839 scan = (*mpack_prefs)->internet_host;
1840 end = (char *) *mpack_prefs + GetHandleSize((Handle) mpack_prefs);
1841 for (i = 0; i < 3; ++i) {
1842 NAgetIText(win->pwin, prefitem[i], P(tmpstr));
1843 SetClen(tmpstr);
1844 len += PCstrlen(tmpstr);
1845 if (scan == end || strcmp(C(tmpstr), scan)) {
1846 changed = 1;
1847 }
1848 while (scan < end && *scan++);
1849 }
1850 if (changed) {
1851 HUnlock((Handle) mpack_prefs);
1852 /* update the preferences resource */
1853 SetHandleSize((Handle) mpack_prefs, sizeof (struct mpack_preferences)
1854 + len);
1855 HLock((Handle) mpack_prefs);
1856 scan = (*mpack_prefs)->internet_host;
1857 useic = icinst && ICBegin(icinst, icReadWritePerm) == noErr;
1858 for (i = 0; i < 3; ++i) {
1859 NAgetIText(win->pwin, prefitem[i], P(tmpstr));
1860 SetClen(tmpstr);
1861 strcpy(scan, C(tmpstr));
1862 scan += PCstrlen(tmpstr) + 1;
1863 if (i && useic) {
1864 ICSetPref(icinst, i == 1 ? kICEmail : kICSMTPHost,
1865 ICattr_no_change, (Ptr) P(tmpstr), PCstrlen(tmpstr) + 1);
1866 }
1867 }
1868 if (useic) ICEnd(icinst);
1869 ChangedResource((Handle) mpack_prefs);
1870 }
1871 HUnlock((Handle) mpack_prefs);
1872 case iCancel:
1873 result = NA_REQCLOSE;
1874 NAmodalMenus(0);
1875 break;
1876 case iAuto:
1877 case iData:
1878 case iSingle:
1879 case iDouble:
1880 NAradioSet(win->pwin, iAuto, iDouble, item);
1881 break;
1882 case iTextEncode:
1883 case iQuitFinish:
1884 SetCtlValue(ctrlh, !GetCtlValue(ctrlh));
1885 break;
1886 case iSet:
1887 NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_HASTASK | NA_USERESOURCE
1888 | NA_MODAL | NA_CHILDWINDOW,
1889 NULL, progDLOG, NULL, sizeof (progresswin), setinit);
1890 break;
1891 }
1892
1893 return (result);
1894 }
1895
1896 /* update preferences dialog
1897 */
1898 static short prefsupdate(na_win *win, Boolean newsize)
1899 {
1900 Handle hn;
1901 Rect box;
1902 short type;
1903
1904 /* draw disabled items */
1905 GetDItem(win->pwin, iEmailAddr, &type, &hn, &box);
1906 if (type == statText) NAhiliteDItem(win->pwin, iEmailAddr, 255);
1907 GetDItem(win->pwin, iMailServer, &type, &hn, &box);
1908 if (type == statText) NAhiliteDItem(win->pwin, iMailServer, 255);
1909
1910 return (NA_NOTPROCESSED);
1911 }
1912
1913 /* initialize preferences dialog
1914 */
1915 static short prefsinit(na_win *win, long *data)
1916 {
1917 PCstr tmpstr[257], eaddr[257];
1918 ControlHandle ctrl;
1919
1920 win->type = PREFWIN;
1921 win->ctrlp = prefsctrl;
1922 win->menup = NAdialogMenu;
1923 win->updatep = prefsupdate;
1924 HLock((Handle) mpack_prefs);
1925 strcpy(C(tmpstr), (*mpack_prefs)->internet_host);
1926 HUnlock((Handle) mpack_prefs);
1927 SetPlen(tmpstr);
1928 NAsetIText(win->pwin, iHost, P(tmpstr));
1929 SelIText(win->pwin, iHost, 0, 32767);
1930 getICprefs(win, eaddr, tmpstr);
1931 NAsetIText(win->pwin, iEmailAddr, P(eaddr));
1932 NAsetIText(win->pwin, iMailServer, P(tmpstr));
1933 NAradioSet(win->pwin, iAuto, iDouble, (*mpack_prefs)->encoding + iAuto);
1934 NAsetIval(win->pwin, iTextEncode, (*mpack_prefs)->extract_text);
1935 NAsetIval(win->pwin, iQuitFinish, (*mpack_prefs)->quit_finished);
1936 if (tcpstart == -1) NAhiliteDItem(win->pwin, iSet, 255);
1937 NAmodalMenus(1);
1938 ShowWindow(win->pwin);
1939
1940 return (NA_NOTPROCESSED);
1941 }
1942
1943 /* Main menu procedure
1944 */
1945 static short mainmenu(na_win *win, WORD menuid, WORD itemno)
1946 {
1947 short status = NA_NOTPROCESSED;
1948 MenuHandle mh;
1949 PCstr version[32];
1950
1951 switch (menuid) {
1952 case 0:
1953 NAenableMItem(mApple, iAbout);
1954 return (status);
1955 case mApple:
1956 if (itemno == iAbout) {
1957 CtoPCstrcpy(version, MPACK_VERSION);
1958 ParamText(P(version), NULL, NULL, NULL);
1959 return (NA_NOTPROCESSED);
1960 }
1961 break;
1962
1963 case mFile:
1964 switch (itemno) {
1965 case iEncode:
1966 do_encode(NULL, 0);
1967 status = NA_PROCESSED;
1968 break;
1969
1970 case iDecode:
1971 do_decode(NULL);
1972 status = NA_PROCESSED;
1973 break;
1974
1975 case iClose:
1976 break;
1977
1978 case iPrefs:
1979 status = NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE
1980 | NA_MODAL | NA_DEFBUTTON | NA_TITLEBAR,
1981 NULL, prefsDLOG, (long *) NULL, 0, prefsinit);
1982 break;
1983
1984 case iQuit:
1985 status = NA_REQCLOSEALL;
1986 break;
1987 }
1988 break;
1989
1990 case mEdit:
1991 break;
1992
1993 case mHelp:
1994 if (!helpw) {
1995 NAwindow(0, NA_USERESOURCE | NATEflags | NATE_READONLY | NA_SMARTSIZE,
1996 NULL, helpWIND, (long *) NULL, sizeof (nate_win), helpwindow);
1997 } else {
1998 SelectWindow(helpw);
1999 }
2000 break;
2001 }
2002 NAdisableMItem(mApple, iAbout);
2003
2004 return (status);
2005 }
2006
2007 /* make preferences folder/file
2008 * returns -1 on failure.
2009 */
2010 static short makepref()
2011 {
2012 Handle hpref = NULL, htmpl;
2013 long dirID;
2014 short vRefNum;
2015 char *scan, *end;
2016 PCstr dname[257];
2017 CInfoPBRec cpb;
2018 DirInfo *dp = &cpb.dirInfo;
2019 ParamBlockRec pb;
2020 VolumeParam *vp = &pb.volumeParam;
2021 FInfo finfo;
2022 static unsigned char pname[] = "\pprefs";
2023
2024 /* set up pref folder storage */
2025 pfolder = (struct pref_folder *) NewPtr(sizeof (struct pref_folder));
2026 if (!pfolder) return (-1);
2027 end = scan = (char *) pfolder->prefs + sizeof (pfolder->prefs) - 1;
2028 *scan = '\0';
2029
2030 /* get pref folder */
2031 if (FindFolder(kOnSystemDisk, kPreferencesFolderType,
2032 kCreateFolder, &vRefNum, &pfolder->fspec.parID) != noErr) {
2033 return (-1);
2034 }
2035
2036 /* create subfolder, if needed */
2037 PtoPCstrcpy(dname, (char *) "\pMpack");
2038 (void) DirCreate(vRefNum, pfolder->fspec.parID, P(dname), &dirID);
2039
2040 /* get mpack prefs folder info */
2041 dp->ioNamePtr = P(dname);
2042 dp->ioVRefNum = vRefNum;
2043 dp->ioFDirIndex = 0;
2044 dp->ioDrDirID = pfolder->fspec.parID;
2045 if (PBGetCatInfoSync(&cpb) != noErr) return (-1);
2046 pfolder->fspec.parID = dirID = dp->ioDrDirID;
2047 pfolder->fspec.vRefNum = vRefNum;
2048
2049 /* generate pathname */
2050 dp->ioFDirIndex = -1;
2051 for (;;) {
2052 *--scan = ':';
2053 if (scan - (char *) pfolder->prefs < 1 + PCstrlen(dname)) return (-1);
2054 scan -= PCstrlen(dname);
2055 memcpy(scan, C(dname), PCstrlen(dname));
2056 if ((dp->ioDrDirID = dp->ioDrParID) == 2) break;
2057 if (PBGetCatInfoSync(&cpb) != noErr) return (-1);
2058 }
2059 vp->ioVolIndex = 0;
2060 vp->ioNamePtr = P(dname);
2061 vp->ioVRefNum = vRefNum;
2062 if (PBGetVInfoSync(&pb) != noErr) return (-1);
2063 *--scan = ':';
2064 if (scan - (char *) pfolder->prefs < 16 + PCstrlen(dname)) return (-1);
2065 PtoPCstrcpy(pfolder->prefs, (char *) P(dname));
2066 CtoPCstrcat(pfolder->prefs, scan);
2067
2068 /* Get/Create preferences file */
2069 HCreateResFile(vRefNum, dirID, pname);
2070 if (ResError() == noErr) {
2071 HGetFInfo(vRefNum, dirID, pname, &finfo);
2072 finfo.fdType = 'pref';
2073 finfo.fdCreator = 'mPAK';
2074 HSetFInfo(vRefNum, dirID, pname, &finfo);
2075 hpref = GetResource('mPRF', prefsID);
2076 DetachResource(hpref);
2077 htmpl = GetResource('TMPL', IDnaID);
2078 DetachResource(htmpl);
2079 }
2080 pfolder->refnum = HOpenResFile(vRefNum, dirID, pname, fsRdWrPerm);
2081 if (pfolder->refnum < 0) return (-1);
2082 if (hpref) {
2083 AddResource(hpref, 'mPRF', prefsID, "\p");
2084 AddResource(htmpl, 'TMPL', IDnaID, "\pIDna");
2085 ReleaseResource(htmpl);
2086 } else {
2087 hpref = GetResource('mPRF', prefsID);
2088 }
2089 if (!hpref) return (-1);
2090 mpack_prefs = (struct mpack_preferences **) hpref;
2091
2092 return (0);
2093 }
2094
2095 /* cleanup shared resources
2096 */
2097 void maccleanup()
2098 {
2099 if (pfolder) {
2100 CloseResFile(pfolder->refnum);
2101 DisposPtr((Ptr) pfolder);
2102 }
2103 if (icinst) ICStop(icinst);
2104 if (tcpstart == 1) NATCPdone(120); /* give 2 seconds to go away */
2105 }
2106
2107 main()
2108 {
2109 CursHandle cursH;
2110
2111 if (NAinit(128, 2, openfile, mainmenu, 3, 1, 0, iClose) == 0) {
2112 /* set up preferences */
2113 if (makepref() < 0) {
2114 yell("Couldn't create preferences file");
2115 } else {
2116 /* set up internet config */
2117 if (ICStart(&icinst, 'mPAK') == noErr) {
2118 (void) ICFindConfigFile(icinst, 0, NULL);
2119 }
2120 /* save watch cursor */
2121 cursH = GetCursor(watchCursor);
2122 watch = **cursH;
2123 /* enter main loop, cleanup on exit */
2124 NAmainloop();
2125 maccleanup();
2126 }
2127 }
2128 }

  ViewVC Help
Powered by ViewVC 1.1.22