Back to home page

MITgcm

 
 

    


File indexing completed on 2018-03-02 18:44:51 UTC

view on githubraw file Latest commit ec6cf3b0 on 2003-08-26 20:45:25 UTC
ec6cf3b09d Ed H*0001 /* macmpack.c -- Mac user interface to mpack routines
                0002  *
                0003  * (C) Copyright 1993-1995 by Carnegie Mellon University
                0004  * All Rights Reserved.
                0005  *
                0006  * Permission to use, copy, modify, distribute, and sell this software
                0007  * and its documentation for any purpose is hereby granted without fee,
                0008  * provided that the above copyright notice appear in all copies and
                0009  * that both that copyright notice and this permission notice appear in
                0010  * supporting documentation, and that the name of Carnegie Mellon University
                0011  * not be used in advertising or publicity pertaining to distribution of the
                0012  * software without specific, written prior permission.  Carnegie
                0013  * Mellon University makes no representations about the suitability of
                0014  * this software for any purpose.  It is provided "as is" without
                0015  * express or implied warranty.
                0016  *
                0017  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
                0018  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                0019  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
                0020  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                0021  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
                0022  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                0023  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
                0024  * SOFTWARE.
                0025  *
                0026  * NOTE: a good GUI requires a lot of work...  This needs more.
                0027  */
                0028 
                0029 #include <Folders.h>
                0030 #include <Script.h>
                0031 #include <GestaltEqu.h>
                0032 
                0033 #include <stdio.h>
                0034 #include <time.h>
                0035 #include <string.h>
                0036 #include <ctype.h>
                0037 #include "version.h"
                0038 #include "part.h"
                0039 #include "macnapp.h"
                0040 #include "macmpack.h"
                0041 #include "macICTypes.h"
                0042 #include "macICAPI.h"
                0043 #include "macICKeys.h"
                0044 
                0045 /* ThinkC's internal stdio functions: */
                0046 #include <ansi_private.h>
                0047 
                0048 /* window types: */
                0049 #define DECODELIST  1
                0050 #define PREFWIN     2
                0051 
                0052 /* save watch cursor */
                0053 Cursor watch;
                0054 
                0055 /* preferences */
                0056 struct pref_folder *pfolder = NULL;
                0057 struct mpack_preferences **mpack_prefs = NULL;
                0058 static ICInstance icinst = NULL;
                0059 
                0060 /* flag for active help window */
                0061 static WindowPtr helpw = NULL;
                0062 
                0063 /* active decode status window */
                0064 static na_win *curstatwin = NULL;
                0065 short didchat;
                0066 
                0067 /* MacTCP started: -1 = error, 1 = active, 0 = unknown */
                0068 static short tcpstart = 0;
                0069 
                0070 /* this is used for opening TEXT files */
                0071 SFTypeList textList = { 'TEXT', 0, 0, 0 };
                0072 
                0073 /* next two types are used in the dialog used to select files to decode
                0074  */
                0075 typedef struct filelist {
                0076     short vRefNum;
                0077     long dirID;
                0078     PCstr fname[65];
                0079 } filelist;
                0080 typedef struct listwin {
                0081     na_win win;
                0082     int count;
                0083     filelist **hflist;
                0084     ListHandle l;
                0085 } listwin;
                0086 
                0087 /* this is the status window for decoding
                0088  */
                0089 typedef struct statuswin {
                0090     na_win win;
                0091     RgnHandle urgn;         /* user region */
                0092     Rect urect;             /* user rectangle */
                0093     Rect frect;             /* frame rectangle */
                0094     short row;              /* row at top of scroll area */
                0095     short nrow;             /* rows of status text */
                0096     long size, used;        /* bytes of status text & amount used */
                0097     Handle text;            /* status text */
                0098     ControlHandle sb;       /* scroll bar control */
                0099     short height, ascent;   /* font height and ascent */
                0100 } statuswin;
                0101 
                0102 /* this is for the encode window
                0103  */
                0104 typedef struct encodewin {
                0105     nate_win w;
                0106     Boolean nateon;             /* cursor in Desc edit field */
                0107     Boolean useemail;           /* sending email */
                0108     long partsize;              /* max part size (0 = no limit) */
                0109     OSType ftype;               /* type of file to encode */
                0110     FSSpec fspec;               /* file to encode */
                0111     FSSpec ofile;               /* output file */
                0112 } encodewin;
                0113 
                0114 /* show progress
                0115  */
                0116 typedef struct progresswin {
                0117     natcp_win w;
                0118     short percent;
                0119 } progresswin;
                0120 
                0121 /* send mail
                0122  */
                0123 typedef struct mailwin {
                0124     progresswin w;
                0125     Handle headers;     /* email headers */
                0126     Handle envelope;    /* envelope */
                0127     short state;        /* state */
                0128     short remaining;    /* messages remaining */
                0129     Boolean sending;    /* flag for active SMTP task */
                0130     Boolean useemail;   /* sending email */
                0131     Boolean gothost;    /* got the hostname */
                0132     long partsize;      /* max part size (0 = no limit) */
                0133     long dirID;         /* ID for temp dir */
                0134     OSType ftype;       /* type of file to encode */
                0135     FSSpec fspec;       /* file to be encoded */
                0136     FSSpec ofile;       /* output file */
                0137     FILE *dfile;        /* desc file */
                0138     PCstr server[257];  /* SMTP server */
                0139     PCstr subj[257];    /* subject */
                0140     CInfoPBRec cpb;
                0141 } mailwin;
                0142 
                0143 /* mailwin states */
                0144 #define MS_MACTCP   0   /* Starting MacTCP */
                0145 #define MS_GETHOST  1   /* Getting hostname */
                0146 #define MS_ENCODE   2   /* Do encoding */
                0147 #define MS_SENDING  3   /* Sending email */
                0148 
                0149 /* some prototypes */
                0150 void warn(char *str);
                0151 void stattext(Str255, unsigned char);
                0152 static void do_decodefiles(na_win *);
                0153 static void addfile(listwin *, FSSpec *);
                0154 static void removefile(listwin *);
                0155 static short listclose(na_win *);
                0156 static short listmouse(na_win *, Point, short, short);
                0157 static short listctrl(na_win *, Point, short, short, ControlHandle);
                0158 static short listupdate(na_win *, Boolean);
                0159 static short listinit(na_win *,long *);
                0160 static short prefsctrl(na_win *, Point, short, short, ControlHandle);
                0161 static short prefsinit(na_win *, long *);
                0162 static void do_decode(FSSpec *);
                0163 static void do_encode(FSSpec *, OSType);
                0164 static short mainmenu(struct na_win*, WORD, WORD);
                0165 
                0166 #define dwin ((listwin *) win)
                0167 #define swin ((statuswin *) win)
                0168 #define ewin ((encodewin *) win)
                0169 #define twin ((nate_win *) win)
                0170 #define prwin ((progresswin *) win)
                0171 #define mwin ((mailwin *) win)
                0172 
                0173 /* Get a FILE* to a Macintosh file
                0174  *******************************     ###############################
                0175  * KLUDGE ALERT! KLUDGE ALERT! *     # KLUDGE ALERT! KLUDGE ALERT! #
                0176  *******************************     ###############################
                0177  * Mac files are specified by name/vRefNum/dirID combo, but the portable
                0178  * portions of mpack use FILE* to do I/O.  We need a way to get an open FILE*
                0179  * from a file specified by name/vRefNum/dirID.  Here we use the proper Macintosh
                0180  * routines to open a file, then hack together a FILE* using ThinkC's internal
                0181  * routines.  The major trouble is that we have no way to get at the FILE action
                0182  * procedure (fp->proc), so we need a sample FILE* to be passed in.  Bleargh!
                0183  *******************************     ###############################
                0184  * KLUDGE ALERT! KLUDGE ALERT! *     # KLUDGE ALERT! KLUDGE ALERT! #
                0185  *******************************     ###############################
                0186  */
                0187 FILE *Macopen(FILE *sample, Str255 name, short vRefNum, long dirID,
                0188                 short binary_flag, short res_fork, SignedByte permission)
                0189 {
                0190     FILE *fp = NULL;
                0191     short refnum;
                0192     long curEOF;
                0193     OSErr err;
                0194     
                0195     if ((!res_fork && (err = HOpen(vRefNum, dirID, name, permission, &refnum)) == noErr)
                0196         || (res_fork && (err = HOpenRF(vRefNum, dirID, name, permission, &refnum)) == noErr)) {
                0197         if ((fp = __getfile()) == NULL) {
                0198             FSClose(refnum);
                0199         } else {
                0200             if (permission == fsWrPerm) {
                0201                 /* if we're writing to the file, truncate it */
                0202                 SetEOF(refnum, curEOF = 0);
                0203             } else {
                0204                 GetEOF(refnum, &curEOF);
                0205             }
                0206             fp->refnum = refnum;
                0207             fp->len = (fpos_t) curEOF;
                0208             fp->binary = binary_flag;
                0209             setvbuf(fp, NULL, _IOFBF, BUFSIZ);
                0210             fp->proc = sample->proc;
                0211         }
                0212     }
                0213     
                0214     return (fp);
                0215 }
                0216 
                0217 
                0218 /* warn the user
                0219  */
                0220 void warn(char *str)
                0221 {
                0222     PCstr wstr[257];
                0223     
                0224     CtoPCstrncpy(wstr, str, 255);
                0225     ParamText(P(wstr), NULL, NULL, NULL);
                0226     NAalert(warnALRT);
                0227 }
                0228 
                0229 /* yell at the user
                0230  */
                0231 void yell(char *str)
                0232 {
                0233     PCstr wstr[257];
                0234     
                0235     CtoPCstrncpy(wstr, str, 255);
                0236     ParamText(P(wstr), NULL, NULL, NULL);
                0237     NAalert(errorALRT);
                0238 }
                0239 
                0240 /* chat with user
                0241  */
                0242 chat(char *str)
                0243 {
                0244     PCstr tmpstr[257];
                0245 
                0246     CtoPCstrcpy(tmpstr, str);
                0247     stattext(P(tmpstr), 0);
                0248 }
                0249 
                0250 /* returns NA_ALLCLOSED if appropriate, else NA_CLOSED
                0251  */
                0252 static short alldone(na_win *win)
                0253 {
                0254     if (win->next == NULL && win->afterp == NULL && (*mpack_prefs)->quit_finished
                0255         && RecoverHandle((Ptr) win) == (Handle) NAhead) {
                0256         return (NA_ALLCLOSED);
                0257     }
                0258     
                0259     return (NA_CLOSED);
                0260 }
                0261 
                0262 /* update procedure for status dialog box
                0263  */
                0264 static short statupdate(na_win *win, Boolean newsize)
                0265 {
                0266     RgnHandle savergn;
                0267     unsigned char *s;
                0268     short row, top;
                0269     Rect tmpr;
                0270     
                0271     FrameRect(&swin->frect);
                0272     savergn = NewRgn();
                0273     if (savergn) {
                0274         GetClip(savergn);
                0275         SetClip(swin->urgn);
                0276     }
                0277     
                0278     /* redraw text area */
                0279     HLock(swin->text);
                0280     s = * (unsigned char **) swin->text;
                0281     top = swin->urect.top;
                0282     for (row = 0; row < swin->row; ++row) {
                0283         s += s[1] + 2;
                0284     }
                0285     for (; row < swin->nrow && top + swin->height <= swin->urect.bottom; ++row) {
                0286         MoveTo(swin->urect.left, top + swin->ascent);
                0287         if (*s) TextFace(1);
                0288         DrawString(s + 1);
                0289         if (*s) TextFace(0);
                0290         /* advance to next string */
                0291         top += swin->height;
                0292         s += s[1] + 2;
                0293     }
                0294     HUnlock(swin->text);
                0295     
                0296     if (savergn) {
                0297         SetClip(savergn);
                0298         DisposeRgn(savergn);
                0299     }
                0300 
                0301     return (NA_NOTPROCESSED);
                0302 }
                0303 
                0304 /* refresh status window
                0305  */
                0306 void statrefresh()
                0307 {
                0308     na_win *win = curstatwin;
                0309     
                0310     Draw1Control(swin->sb);
                0311     statupdate(win, false);
                0312 }
                0313 
                0314 /* add text to the status window
                0315  */
                0316 void stattext(Str255 str, unsigned char bold)
                0317 {
                0318     na_win *win = curstatwin;
                0319     short i, len;
                0320     unsigned char *s, *start;
                0321     RgnHandle rgn;
                0322     Rect tmpr;
                0323     
                0324     if (!win) return;
                0325     didchat = 1;
                0326     
                0327     /* advance to next row */
                0328     if (swin->height * (swin->nrow++ - swin->row)
                0329         >= swin->urect.bottom - swin->urect.top) {
                0330         SetCtlMax(swin->sb, ++swin->row);
                0331         SetCtlValue(swin->sb, swin->row);
                0332         if ((rgn = NewRgn()) != NULL) {
                0333             tmpr = swin->urect;
                0334             ScrollRect(&tmpr, 0, -swin->height, rgn);
                0335             DisposeRgn(rgn);
                0336         }
                0337     }
                0338     
                0339     /* add the text */
                0340     len = * (unsigned char *) str;
                0341     if (swin->size - swin->used < len + 1) {
                0342         SetHandleSize(swin->text, swin->size * 2);
                0343         if (MemError() == 0) swin->size *= 2;
                0344     }
                0345     HLock(swin->text);
                0346     s = start = * (unsigned char **) swin->text;
                0347     for (i = 1; i < swin->nrow; ++i) {
                0348         s += s[1] + 2;
                0349     }
                0350     if (len + 2 + s < start + swin->size) {
                0351         *s = bold;
                0352         memcpy(s + 1, str, len + 1);
                0353         swin->used = s + len + 2 - start;
                0354     }
                0355     HUnlock(swin->text);
                0356     statupdate(win, false);
                0357 }
                0358 
                0359 /* scroll the status dialog
                0360  */
                0361 static void statscroll(na_win *win, short rows)
                0362 {
                0363     RgnHandle rgn;
                0364     
                0365     if ((rgn = NewRgn()) != NULL) {
                0366         SetCtlValue(swin->sb, swin->row += rows);
                0367         ScrollRect(&swin->urect, 0, - swin->height * rows, rgn);
                0368         EraseRgn(rgn);
                0369         DisposeRgn(rgn);
                0370     }
                0371     statupdate(win, false);
                0372 }
                0373 
                0374 /* scroll bar procedure
                0375  */
                0376 static pascal void statscollbar(ControlHandle ctrlh, short part)
                0377 {
                0378     na_win *win = (na_win *) GetCRefCon(ctrlh);
                0379     short max, new, page;
                0380     
                0381     max = GetCtlMax(ctrlh);
                0382     page = (swin->urect.bottom - swin->urect.top) / swin->height - 1;
                0383     switch (part) {
                0384         case inUpButton:
                0385             page = 1;
                0386             /* fall through */
                0387         case inPageUp:
                0388             if (swin->row > 0) {
                0389                 statscroll(win, - (swin->row < page ? swin->row : page));
                0390             }
                0391             break;
                0392         case inDownButton:
                0393             page = 1;
                0394             /* fall through */
                0395         case inPageDown:
                0396             if (swin->row < max) {
                0397                 statscroll(win, max - swin->row < page ? max - swin->row : page);
                0398             }
                0399             break;
                0400         case inThumb:
                0401             break;
                0402     }
                0403 }
                0404 
                0405 /* control procedure for status dialog box
                0406  */
                0407 static short statctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
                0408 {
                0409     short value;
                0410     
                0411     if (ctrlh == swin->sb) {
                0412         ctrlh = swin->sb;
                0413         if (item != inThumb) {
                0414             SetCRefCon(ctrlh, (long) win);
                0415             TrackControl(ctrlh, p, statscollbar);
                0416         } else {
                0417             TrackControl(ctrlh, p, nil);
                0418             value = GetCtlValue(ctrlh);
                0419             if (value != swin->row) statscroll(win, value - swin->row);
                0420         }
                0421     } else if (item == iOk) {
                0422         return (NA_REQCLOSE);
                0423     }
                0424     
                0425     return (NA_NOTPROCESSED);
                0426 }
                0427 
                0428 /* close procedure for status dialog box
                0429  */
                0430 static short statclose(na_win *win)
                0431 {
                0432     DisposeRgn(swin->urgn);
                0433     DisposHandle(swin->text);
                0434     DisposeControl(swin->sb);
                0435     
                0436     return (alldone(win));
                0437 }
                0438 
                0439 /* init procedure for status dialog box
                0440  */
                0441 static short statinit(na_win *win, long *data)
                0442 {
                0443     Rect tmpr;
                0444     FontInfo finfo;
                0445     
                0446     /* disable OK button while working */
                0447     NAhiliteDItem(win->pwin, iOk, 255);
                0448     
                0449     /* set up status text area & font */
                0450     if ((swin->urgn = NewRgn()) == NULL) return (NA_CLOSED);
                0451     TextFont(geneva);
                0452     TextSize(9);
                0453     GetFontInfo(&finfo);
                0454     swin->ascent = finfo.ascent;
                0455     swin->height = finfo.ascent + finfo.descent + finfo.leading;
                0456     NAgetDRect(win->pwin, iStatus, &swin->frect);
                0457     swin->urect = swin->frect;
                0458     InsetRect(&swin->urect, 2, 
                0459         2 + ((swin->urect.bottom - swin->urect.top - 4) % swin->height) / 2);
                0460     RectRgn(swin->urgn, &swin->urect);
                0461 
                0462     /* set up text storage */
                0463     if ((swin->text = NewHandle(swin->size = 1024)) == NULL) {
                0464         DisposeRgn(swin->urgn);
                0465         return (NA_CLOSED);
                0466     }
                0467     **(char **)swin->text = '\0';
                0468     
                0469     /* set up scrollbar */
                0470     NAgetDRect(win->pwin, iStatScroll, &tmpr);
                0471     swin->sb = NewControl(win->pwin, &tmpr, "\p", true, 0, 0, 0, scrollBarProc, 0);
                0472     if (!swin->sb) {
                0473         DisposeRgn(swin->urgn);
                0474         DisposHandle(swin->text);
                0475         return (NA_CLOSED);
                0476     }
                0477     
                0478     /* set up procedures */
                0479     win->closep = statclose;
                0480     win->ctrlp = statctrl;
                0481     win->updatep = statupdate;
                0482     
                0483     /* keep window locked until decoding is done */
                0484     ++win->locks;
                0485     curstatwin = win;
                0486     
                0487     return (NA_NOTPROCESSED);
                0488 }
                0489 
                0490 /* process the files in the file list
                0491  */
                0492 static void do_decodefiles(na_win *win)
                0493 {
                0494     int count = dwin->count;
                0495     filelist *fl;
                0496     FILE *dfile, *tmpf;
                0497     extern long _ftype, _fcreator;
                0498     long ticks;
                0499     int result;
                0500     
                0501     MapTypeCreator("text/plain", 0);
                0502     SetCursor(&watch);
                0503     if (NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_DEFBUTTON | NA_USERESOURCE
                0504         | NA_CLOSEBOX | NA_HASCONTROLS,
                0505         0, dstatDLOG, 0, sizeof (statuswin), statinit) == NA_CLOSED) {
                0506         warn("Not enough memory to decode");
                0507         return;
                0508     }
                0509     MoveHHi((Handle) dwin->hflist);
                0510     HLock((Handle) dwin->hflist);
                0511     fl = *dwin->hflist;
                0512     tmpf = tmpfile();
                0513     while (count--) {
                0514         stattext(fl->fname, 1);
                0515         didchat = 0;
                0516         if (dfile = Macopen(tmpf, fl->fname, fl->vRefNum, fl->dirID, 0, 0, 1)) {
                0517             result = handleMessage(part_init(dfile), "text/plain",
                0518                 0, (*mpack_prefs)->extract_text);
                0519             if (result != 0 || didchat <= 0) {
                0520                 if (didchat < 0) {
                0521                     chat("Decoding cancelled");
                0522                 } else {
                0523                     chat("Found nothing to decode");
                0524                 }
                0525             }
                0526             fclose(dfile);
                0527         } else {
                0528             chat("Couldn't find source file");
                0529         }
                0530         ++fl;
                0531     }
                0532     fclose(tmpf);
                0533     HUnlock((Handle) dwin->hflist);
                0534     NAhiliteDItem(curstatwin->pwin, iOk, 0);
                0535     NAunlockWindow(curstatwin);
                0536     curstatwin = NULL;
                0537     SetCursor(&arrow);
                0538     DisposHandle((Handle) dwin->hflist);
                0539 }
                0540 
                0541 /* return non-zero if two filenames have the same prefix
                0542  */
                0543 static int fprefixMatch(char *base, PCstr *match)
                0544 {
                0545     PCstr temp[257];
                0546     char *scan;
                0547     short prefixlen;
                0548     
                0549     PtoPCstrcpy(temp, base);
                0550     scan = C(temp) + PCstrlen(temp) - 1;
                0551     while (isdigit(*scan) && scan > C(temp)) --scan;
                0552     prefixlen = scan - C(temp) + 1;
                0553     if (strncmp(C(temp), C(match), prefixlen)) return (0);
                0554     scan = C(match) + prefixlen;
                0555     while (isdigit(*scan)) ++scan;
                0556     
                0557     return (!*scan);
                0558 }
                0559 
                0560 /* do the add of a file to a list
                0561  */
                0562 static void addit(listwin *dw, short vRefNum, long dirID, char *fname)
                0563 {
                0564     long size = GetHandleSize((Handle) dw->hflist) / sizeof (filelist);
                0565     filelist *fl;
                0566     char *bp;
                0567     Cell c;
                0568     int i;
                0569     PCstr fbuf[42];
                0570 
                0571     if (size == dw->count) {
                0572         SetHandleSize((Handle) dw->hflist, (++size * sizeof (filelist)));
                0573         if (MemError() != noErr) return;
                0574     }
                0575     MoveHHi((Handle) dw->hflist);
                0576     HLock((Handle) dw->hflist);
                0577     fl = *dw->hflist;
                0578     for (i = dw->count; i; --i, ++fl) {
                0579         if (fl->vRefNum == vRefNum && fl->dirID == dirID &&
                0580             *fl->fname == *fname && !strncmp(C(fl->fname), C(fname), *fl->fname)) {
                0581             break;
                0582         }
                0583     }
                0584     if (!i) {
                0585         fl->vRefNum = vRefNum;
                0586         fl->dirID = dirID;
                0587         PtoPCstrcpy(fl->fname, fname);
                0588         SetPt(&c, 0, dw->count);
                0589         LAddRow(1, ++dw->count, dw->l);
                0590         LSetCell((Ptr) C(fname), (short) Pstrlen(fname), c, dw->l);
                0591     }
                0592     HUnlock((Handle) dw->hflist);
                0593 }
                0594 
                0595 /* add file set to file list
                0596  */
                0597 static void addfile(dw, fspec)
                0598     listwin *dw;
                0599     FSSpec *fspec;
                0600 {
                0601     CInfoPBRec cipbr;
                0602     HFileInfo *fpb = (HFileInfo *)&cipbr;
                0603     PCstr fbuf[42];
                0604     short idx, foundone = 0;
                0605     long procid;
                0606     
                0607     /* remove working directory stuff */
                0608     if (fspec->parID == 0) {
                0609         GetWDInfo(fspec->vRefNum, &fspec->vRefNum, &fspec->parID, &procid);
                0610     }
                0611 
                0612     /* loop through directory */
                0613     for (idx = 1; ; ++idx) {
                0614         fpb->ioVRefNum = fspec->vRefNum;
                0615         fpb->ioNamePtr = P(fbuf);
                0616         fpb->ioDirID = fspec->parID;
                0617         fpb->ioFDirIndex = idx;
                0618         if (PBGetCatInfoSync(&cipbr)) break;
                0619         SetClen(fbuf);
                0620         
                0621         if (!(fpb->ioFlAttrib & 16) && fprefixMatch((char *)fspec->name, fbuf)) {
                0622             addit(dw, fspec->vRefNum, fspec->parID, (char *) P(fbuf));
                0623             foundone = 1;
                0624         }
                0625     }
                0626     if (!foundone) {
                0627         addit(dw, fspec->vRefNum, fspec->parID, (char *) fspec->name);
                0628     }
                0629 }
                0630 
                0631 /* remove file from file list
                0632  */
                0633 static void removefile(dw)
                0634     listwin *dw;
                0635 {
                0636     filelist *fl;
                0637     int count;
                0638     Cell c;
                0639     
                0640     c.h = c.v = 0;
                0641     if (LGetSelect(TRUE, &c, dw->l)) {
                0642         MoveHHi((Handle) dw->hflist);
                0643         HLock((Handle) dw->hflist);
                0644         fl = *dw->hflist + c.v;
                0645         count = dw->count - c.v;
                0646         while (--count) {
                0647             fl[0] = fl[1];
                0648             ++fl;
                0649         }
                0650         HUnlock((Handle) dw->hflist);       
                0651         --dw->count;
                0652         LDelRow(1, c.v, dw->l);
                0653     }
                0654 }
                0655 
                0656 /* close list window
                0657  */
                0658 static short listclose(win)
                0659     na_win *win;
                0660 {
                0661     LDispose(dwin->l);
                0662     
                0663     return (alldone(win));
                0664 }
                0665 
                0666 /* mouse procedure
                0667  */
                0668 static short listmouse(na_win *win, Point p, short type, short mods)
                0669 {
                0670     Cell c;
                0671     
                0672     if (!(type & 1)) {
                0673         LClick(p, mods, dwin->l);
                0674         c.h = c.v = 0;
                0675         NAhiliteDItem((DialogPtr)win->pwin, iRemove, LGetSelect(TRUE, &c, dwin->l) ? 0 : 255);
                0676     }
                0677     
                0678     return (NA_NOTPROCESSED);
                0679 }
                0680 
                0681 /* control procedure
                0682  */
                0683 static short listctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
                0684 {
                0685     StandardFileReply reply;
                0686 
                0687     switch (item) {
                0688         case iAdd:
                0689             NAgetFile(NULL, 1, textList, &reply);
                0690             if (reply.sfGood) {
                0691                 if (!dwin->count) {
                0692                     NAhiliteDItem((DialogPtr)win->pwin, iOk, 0);
                0693                 }
                0694                 addfile(dwin, &reply.sfFile);
                0695             }
                0696             return (NA_PROCESSED);
                0697             
                0698         case iRemove:
                0699             removefile(dwin);
                0700             NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
                0701             if (!dwin->count) {
                0702                 NAhiliteDItem((DialogPtr)win->pwin, iOk, 255);
                0703             }
                0704             return (NA_PROCESSED);
                0705 
                0706         case iOk:
                0707             win->afterp = do_decodefiles;
                0708         case iCancel:
                0709             return (NA_REQCLOSE);
                0710     }
                0711     
                0712     return (NA_NOTPROCESSED);
                0713 }
                0714 
                0715 /* update the list window
                0716  */
                0717 static short listupdate(na_win *win, Boolean resize)
                0718 {
                0719     Rect r;
                0720     
                0721     NAgetDRect(win->pwin, iFileList, &r);
                0722     FrameRect(&r);
                0723     LUpdate(win->pwin->visRgn, dwin->l);
                0724     
                0725     return (NA_NOTPROCESSED);
                0726 }
                0727 
                0728 /* initialize the list window
                0729  */
                0730 static short listinit(win, data)
                0731     na_win *win;
                0732     long *data;
                0733 {
                0734     FSSpec *fspec = (FSSpec *) data;
                0735     Rect r, zrect;
                0736     Point p;
                0737     Handle hand;
                0738     short type;
                0739     
                0740     GetDItem((DialogPtr)win->pwin, iFileList, &type, &hand, &r);
                0741     InsetRect(&r, 1, 1);
                0742     zrect.top = zrect.bottom = zrect.left = p.h = p.v = 0;\
                0743     zrect.right = 1;
                0744     dwin->l = LNew(&r, &zrect, p, 0, win->pwin, 0, 0, 0, 1);
                0745     if (!dwin->l) return (NA_CLOSED);
                0746     (*dwin->l)->selFlags = lOnlyOne;
                0747     dwin->hflist = (filelist **) NewHandle(sizeof (filelist));
                0748     if (!dwin->hflist) {
                0749         LDispose(dwin->l);
                0750         return (NA_CLOSED);
                0751     }
                0752     dwin->count = 0;
                0753     addfile(dwin, fspec);
                0754     win->closep = listclose;
                0755     win->updatep = listupdate;
                0756     win->ctrlp = listctrl;
                0757     win->mousep = listmouse;
                0758     win->type = DECODELIST;
                0759     NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
                0760     ShowWindow(win->pwin);
                0761     LDoDraw(TRUE, dwin->l);
                0762     
                0763     return (NA_NOTPROCESSED);
                0764 }
                0765 
                0766 /* Decode procedure: first get a file, then open decode window
                0767  */
                0768 static void do_decode(FSSpec *fspec)
                0769 {
                0770     StandardFileReply infile;
                0771     na_win **wh, *wp;
                0772     
                0773     if (!fspec) {
                0774         NAgetFile(NULL, 1, textList, &infile);
                0775         if (!infile.sfGood) return;
                0776         fspec = &infile.sfFile;
                0777     } else {
                0778         /* file supplied by drag & drop, look for existing decode window: */
                0779         for (wh = NAhead; wh && (*wh)->type != DECODELIST; wh = (*wh)->next);
                0780         if (wh && (wp = NAlockWindow(wh)) != NULL) {
                0781             addfile((listwin *) wp, fspec);
                0782             NAunlockWindow(wp);
                0783             return;
                0784         }
                0785     }
                0786     NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_DEFBUTTON |
                0787         NA_HASCONTROLS | NA_CLOSEBOX, NULL, decodeDLOG, (long *) fspec,
                0788         sizeof (listwin), listinit);
                0789 }
                0790 
                0791 /* Map MIME type to/from Macintosh file types
                0792  */
                0793 void MapTypeCreator(char *contenttype, OSType type)
                0794 {
                0795     extern long _ftype, _fcreator;
                0796     PCstr tstr[257];
                0797     Handle h;
                0798     ICAttr attr;
                0799     long size = 0;
                0800     Ptr map;
                0801     ICMapEntry *ment;
                0802     unsigned char *scan, *end, *pstr;
                0803     short mapcount, i, foundit = 0;
                0804     OSType temp;
                0805     
                0806     if (!type) CtoPCstrncpy(tstr, contenttype, 255);
                0807     
                0808     /* first try a lookup via Internet Config */
                0809     if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
                0810         if (ICGetPref(icinst, kICMapping, &attr, nil, &size) == noErr
                0811             && size > 0 && (map = NewPtr(size)) != nil) {
                0812             if (ICGetPref(icinst, kICMapping, &attr, map, &size) == noErr) {
                0813                 scan = (unsigned char *) map;
                0814                 end = scan + size;
                0815                 while (scan < end) {
                0816                     ment = (ICMapEntry *) scan;
                0817                     pstr = scan + ment->fixed_length;
                0818                     scan += ment->total_length;
                0819                     if (type && ment->file_type != type) continue;
                0820                     pstr += *pstr + 1; /* skip over extension */
                0821                     pstr += *pstr + 1; /* skip over creator app name */
                0822                     pstr += *pstr + 1; /* skip over post app name */
                0823                     if (type) {
                0824                         PtoPCstrcpy((PCstr *) contenttype, (char *) pstr);
                0825                         foundit = 1;
                0826                         break;
                0827                     } else if (EqualString(P(tstr), pstr, false, true)) {
                0828                         _ftype = ment->file_type;
                0829                         _fcreator = ment->file_creator;
                0830                         foundit = 1;
                0831                         break;
                0832                     }
                0833                 }
                0834             }
                0835             DisposPtr(map);
                0836         }
                0837         ICEnd(icinst);
                0838     }
                0839     
                0840     /* if we didn't find it, try our quick&dirty mappings */
                0841     if (!foundit) {
                0842         if (type) {
                0843             mapcount = CountResources('TyCr');
                0844             for (i = 1; i <= mapcount; ++i) {
                0845                 h = GetIndResource('TyCr', i);
                0846                 if (h && **(OSType **)h == type) {
                0847                     GetResInfo(h, &i, &temp, P(contenttype));
                0848                     if (ResError() == noErr) break;
                0849                 }
                0850             }
                0851             SetClen((PCstr *) contenttype);
                0852         } else {
                0853             h = GetNamedResource('TyCr', P(tstr));
                0854             if (h) {
                0855                 _ftype = (*(OSType **)h)[0];
                0856                 _fcreator = (*(OSType **)h)[1];
                0857             } else {
                0858                 _ftype = '????';
                0859                 _fcreator = 'mPAK';
                0860             }
                0861         }
                0862     }
                0863 }
                0864 
                0865 /* get internet config string prefs
                0866  */
                0867 static short getICprefs(na_win *win, PCstr *eaddr, PCstr *smtphost)
                0868 {
                0869     char *scan, *end;
                0870     ICAttr attr;
                0871     long size;
                0872     ICError err = noErr;
                0873     
                0874     *C(eaddr) = '\0';
                0875     SetPlen(eaddr);
                0876     *C(smtphost) = '\0';
                0877     SetPlen(smtphost);
                0878     if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
                0879         size = 256;
                0880         if (ICGetPref(icinst, kICEmail, &attr, (Ptr) eaddr, &size) == noErr
                0881             && win && (attr & ICattr_locked_mask)) {
                0882             NAenableDItem(win->pwin, iEmailAddr, 0);
                0883         }
                0884         SetClen(eaddr);
                0885         size = 256;
                0886         if (ICGetPref(icinst, kICSMTPHost, &attr, (Ptr) smtphost, &size) == noErr
                0887             && win && (attr & ICattr_locked_mask)) {
                0888             NAenableDItem(win->pwin, iMailServer, 0);
                0889         }
                0890         SetClen(smtphost);
                0891         ICEnd(icinst);
                0892     } else {
                0893         HLock((Handle) mpack_prefs);
                0894         end = (char *) (*mpack_prefs) + GetHandleSize((Handle) mpack_prefs);
                0895         scan = (*mpack_prefs)->internet_host;
                0896         while (scan < end && *scan++);
                0897         if (scan < end) CtoPCstrcpy(eaddr, scan);
                0898         while (scan < end && *scan++);
                0899         if (scan < end) CtoPCstrcpy(smtphost, scan);
                0900         HUnlock((Handle) mpack_prefs);
                0901     }
                0902 }
                0903 
                0904 /* copy desc file, with word-wrap
                0905  */
                0906 static short copydesc(FILE *out, TEHandle hTE)
                0907 {
                0908     char c;
                0909     short i, count, word, col, reset;
                0910     char **htxt;
                0911     
                0912     count = (*hTE)->teLength;
                0913     htxt = (char **) (*hTE)->hText;
                0914     for (i = word = col = 0; i < count; ++i) {
                0915         c = (*htxt)[i];
                0916         reset = i - word == 80 || c == '\r';
                0917         if (reset || c == ' ') {
                0918             while (word < i) putc((*htxt)[word], out), ++word;
                0919         }
                0920         if (reset || ++col == 80) {
                0921             putc('\r', out);
                0922             c = (*htxt)[word];
                0923             if (c == ' ' || c == '\r') ++word;
                0924             col = 0;
                0925         }
                0926     }
                0927     while (word < i) putc((*htxt)[word], out), ++word;
                0928     rewind(out);
                0929 }
                0930 
                0931 /* start up MacTCP callback
                0932  */
                0933 static void mytcpinit(short status)
                0934 {
                0935     static DialogPtr dialog = NULL;
                0936     GrafPtr save;
                0937     Rect box;
                0938     
                0939     if (status < 0) {
                0940         tcpstart = -1;
                0941     } else if (status == 0) {
                0942         tcpstart = 1;
                0943     } else {
                0944         if (!dialog && status < 100) {
                0945             dialog = GetNewDialog(progDLOG, nil, (WindowPtr) -1);
                0946             NAsetIText(dialog, iWorkText, "\pWaiting for MacTCP to finish.  Press \021. to stop.");
                0947         }
                0948         if (dialog) {
                0949             GetPort(&save);
                0950             SetPort(dialog);
                0951             NAgetDRect(dialog, iProgress, &box);
                0952             FrameRect(&box);
                0953             InsetRect(&box, 1, 1);
                0954             box.right = box.left + (box.right - box.left) * status / 100;
                0955             FillRect(&box, qd.dkGray);
                0956             SetPort(save);
                0957             if (status == 100) {
                0958                 DisposDialog(dialog);
                0959                 dialog = NULL;
                0960             }
                0961         }
                0962     }
                0963 }
                0964 
                0965 /* update the progress bar
                0966  */
                0967 static short progressupdate(na_win *win, Boolean newsize)
                0968 {
                0969     Rect box;
                0970     
                0971     if (prwin->percent >= 0) {
                0972         NAgetDRect(win->pwin, iProgress, &box);
                0973         FrameRect(&box);
                0974         InsetRect(&box, 1, 1);
                0975         if (prwin->percent) {
                0976             box.right = box.left + (box.right - box.left) * prwin->percent / 100;
                0977             FillRect(&box, qd.dkGray);
                0978         } else {
                0979             EraseRect(&box);
                0980         }
                0981     }
                0982     
                0983     return (NA_NOTPROCESSED);
                0984 }
                0985 
                0986 /* handle the cancel button
                0987  */
                0988 static short progressctrl(na_win *win, Point p, short item, short mods,
                0989     ControlHandle ctrlh)
                0990 {
                0991     return (item == iCancel ? NA_REQCLOSE : NA_NOTPROCESSED);
                0992 }
                0993 
                0994 /* close progress window
                0995  */
                0996 static short progressclose(na_win *win)
                0997 {
                0998     NAmodalMenus(0);
                0999     
                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 }