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  */
Macopen(FILE * sample,Str255 name,short vRefNum,long dirID,short binary_flag,short res_fork,SignedByte permission)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  */
warn(char * str)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  */
yell(char * str)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  */
chat(char * str)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  */
alldone(na_win * win)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  */
statupdate(na_win * win,Boolean newsize)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  */
statrefresh()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  */
stattext(Str255 str,unsigned char bold)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  */
statscroll(na_win * win,short rows)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  */
statscollbar(ControlHandle ctrlh,short part)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  */
statctrl(na_win * win,Point p,short item,short mods,ControlHandle ctrlh)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  */
statclose(na_win * win)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  */
statinit(na_win * win,long * data)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  */
do_decodefiles(na_win * win)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  */
fprefixMatch(char * base,PCstr * match)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  */
addit(listwin * dw,short vRefNum,long dirID,char * fname)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  */
addfile(dw,fspec)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  */
removefile(dw)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  */
listclose(win)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  */
listmouse(na_win * win,Point p,short type,short mods)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  */
listctrl(na_win * win,Point p,short item,short mods,ControlHandle ctrlh)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  */
listupdate(na_win * win,Boolean resize)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  */
listinit(win,data)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  */
do_decode(FSSpec * fspec)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  */
MapTypeCreator(char * contenttype,OSType type)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  */
getICprefs(na_win * win,PCstr * eaddr,PCstr * smtphost)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  */
copydesc(FILE * out,TEHandle hTE)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  */
mytcpinit(short status)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  */
progressupdate(na_win * win,Boolean newsize)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  */
progressctrl(na_win * win,Point p,short item,short mods,ControlHandle ctrlh)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  */
progressclose(na_win * win)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  */
prefsubdir(PCstr * name,long * dirID)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  */
smtpstat(void * wh,short code,short err,long num,char * errstr)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  */
mailhost(void * user,na_tcp s,short status,long size,char * data)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  */
mailclose(na_win * win)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  */
mailtask(na_win * win)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  */
rfc822_date(char * string)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  */
mailinit(na_win * win,long * data)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  */
encodeupdate(na_win * win,Boolean newsize)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  */
seldesctext(na_win * win)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  */
encodectrl(na_win * win,Point p,short item,short mods,ControlHandle ctrlh)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  */
encodekey(na_win * win,long c,short mods)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  */
encodemenu(na_win * win,WORD menu,WORD item)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  */
encodemouse(na_win * win,Point p,short type,short mods)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  */
encodeclose(na_win * win)1603 static short encodeclose(na_win *win)
1604 {
1605 	NATEclosep(win);
1606 
1607 	return (NA_CLOSED);
1608 }
1609 
1610 /* init the encode window
1611  */
encodeinit(na_win * win,long * data)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  */
do_encode(FSSpec * fspec,OSType ftype)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  */
openfile(short message,FSSpec * fspec,FInfo * finfo)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  */
helpclose(na_win * win)1699 static short helpclose(na_win *win)
1700 {
1701 	helpw = NULL;
1702 
1703 	return (NATEclosep(win));
1704 }
1705 
1706 /* help window procedure
1707  */
helpwindow(na_win * win,long * data)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  */
sethost(void * user,na_tcp s,short status,long size,char * data)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  */
settask(na_win * win)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  */
setinit(na_win * win,long * data)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  */
prefsctrl(na_win * win,Point p,short item,short mods,ControlHandle ctrlh)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  */
prefsupdate(na_win * win,Boolean newsize)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  */
prefsinit(na_win * win,long * data)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  */
mainmenu(na_win * win,WORD menuid,WORD itemno)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  */
makepref()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  */
maccleanup()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 
main()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 }
2129