home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
Amiga
/
Workbench
/
Archivers
/
mpackWOS.lha
/
mpackppc
/
src
/
macmpack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-04-08
|
54KB
|
2,129 lines
/* macmpack.c -- Mac user interface to mpack routines
*
* (C) Copyright 1993-1995 by Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of Carnegie Mellon University
* not be used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. Carnegie
* Mellon University makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* NOTE: a good GUI requires a lot of work... This needs more.
*/
#include <Folders.h>
#include <Script.h>
#include <GestaltEqu.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "version.h"
#include "part.h"
#include "macnapp.h"
#include "macmpack.h"
#include "macICTypes.h"
#include "macICAPI.h"
#include "macICKeys.h"
/* ThinkC's internal stdio functions: */
#include <ansi_private.h>
/* window types: */
#define DECODELIST 1
#define PREFWIN 2
/* save watch cursor */
Cursor watch;
/* preferences */
struct pref_folder *pfolder = NULL;
struct mpack_preferences **mpack_prefs = NULL;
static ICInstance icinst = NULL;
/* flag for active help window */
static WindowPtr helpw = NULL;
/* active decode status window */
static na_win *curstatwin = NULL;
short didchat;
/* MacTCP started: -1 = error, 1 = active, 0 = unknown */
static short tcpstart = 0;
/* this is used for opening TEXT files */
SFTypeList textList = { 'TEXT', 0, 0, 0 };
/* next two types are used in the dialog used to select files to decode
*/
typedef struct filelist {
short vRefNum;
long dirID;
PCstr fname[65];
} filelist;
typedef struct listwin {
na_win win;
int count;
filelist **hflist;
ListHandle l;
} listwin;
/* this is the status window for decoding
*/
typedef struct statuswin {
na_win win;
RgnHandle urgn; /* user region */
Rect urect; /* user rectangle */
Rect frect; /* frame rectangle */
short row; /* row at top of scroll area */
short nrow; /* rows of status text */
long size, used; /* bytes of status text & amount used */
Handle text; /* status text */
ControlHandle sb; /* scroll bar control */
short height, ascent; /* font height and ascent */
} statuswin;
/* this is for the encode window
*/
typedef struct encodewin {
nate_win w;
Boolean nateon; /* cursor in Desc edit field */
Boolean useemail; /* sending email */
long partsize; /* max part size (0 = no limit) */
OSType ftype; /* type of file to encode */
FSSpec fspec; /* file to encode */
FSSpec ofile; /* output file */
} encodewin;
/* show progress
*/
typedef struct progresswin {
natcp_win w;
short percent;
} progresswin;
/* send mail
*/
typedef struct mailwin {
progresswin w;
Handle headers; /* email headers */
Handle envelope; /* envelope */
short state; /* state */
short remaining; /* messages remaining */
Boolean sending; /* flag for active SMTP task */
Boolean useemail; /* sending email */
Boolean gothost; /* got the hostname */
long partsize; /* max part size (0 = no limit) */
long dirID; /* ID for temp dir */
OSType ftype; /* type of file to encode */
FSSpec fspec; /* file to be encoded */
FSSpec ofile; /* output file */
FILE *dfile; /* desc file */
PCstr server[257]; /* SMTP server */
PCstr subj[257]; /* subject */
CInfoPBRec cpb;
} mailwin;
/* mailwin states */
#define MS_MACTCP 0 /* Starting MacTCP */
#define MS_GETHOST 1 /* Getting hostname */
#define MS_ENCODE 2 /* Do encoding */
#define MS_SENDING 3 /* Sending email */
/* some prototypes */
void warn(char *str);
void stattext(Str255, unsigned char);
static void do_decodefiles(na_win *);
static void addfile(listwin *, FSSpec *);
static void removefile(listwin *);
static short listclose(na_win *);
static short listmouse(na_win *, Point, short, short);
static short listctrl(na_win *, Point, short, short, ControlHandle);
static short listupdate(na_win *, Boolean);
static short listinit(na_win *,long *);
static short prefsctrl(na_win *, Point, short, short, ControlHandle);
static short prefsinit(na_win *, long *);
static void do_decode(FSSpec *);
static void do_encode(FSSpec *, OSType);
static short mainmenu(struct na_win*, WORD, WORD);
#define dwin ((listwin *) win)
#define swin ((statuswin *) win)
#define ewin ((encodewin *) win)
#define twin ((nate_win *) win)
#define prwin ((progresswin *) win)
#define mwin ((mailwin *) win)
/* Get a FILE* to a Macintosh file
******************************* ###############################
* KLUDGE ALERT! KLUDGE ALERT! * # KLUDGE ALERT! KLUDGE ALERT! #
******************************* ###############################
* Mac files are specified by name/vRefNum/dirID combo, but the portable
* portions of mpack use FILE* to do I/O. We need a way to get an open FILE*
* from a file specified by name/vRefNum/dirID. Here we use the proper Macintosh
* routines to open a file, then hack together a FILE* using ThinkC's internal
* routines. The major trouble is that we have no way to get at the FILE action
* procedure (fp->proc), so we need a sample FILE* to be passed in. Bleargh!
******************************* ###############################
* KLUDGE ALERT! KLUDGE ALERT! * # KLUDGE ALERT! KLUDGE ALERT! #
******************************* ###############################
*/
FILE *Macopen(FILE *sample, Str255 name, short vRefNum, long dirID,
short binary_flag, short res_fork, SignedByte permission)
{
FILE *fp = NULL;
short refnum;
long curEOF;
OSErr err;
if ((!res_fork && (err = HOpen(vRefNum, dirID, name, permission, &refnum)) == noErr)
|| (res_fork && (err = HOpenRF(vRefNum, dirID, name, permission, &refnum)) == noErr)) {
if ((fp = __getfile()) == NULL) {
FSClose(refnum);
} else {
if (permission == fsWrPerm) {
/* if we're writing to the file, truncate it */
SetEOF(refnum, curEOF = 0);
} else {
GetEOF(refnum, &curEOF);
}
fp->refnum = refnum;
fp->len = (fpos_t) curEOF;
fp->binary = binary_flag;
setvbuf(fp, NULL, _IOFBF, BUFSIZ);
fp->proc = sample->proc;
}
}
return (fp);
}
/* warn the user
*/
void warn(char *str)
{
PCstr wstr[257];
CtoPCstrncpy(wstr, str, 255);
ParamText(P(wstr), NULL, NULL, NULL);
NAalert(warnALRT);
}
/* yell at the user
*/
void yell(char *str)
{
PCstr wstr[257];
CtoPCstrncpy(wstr, str, 255);
ParamText(P(wstr), NULL, NULL, NULL);
NAalert(errorALRT);
}
/* chat with user
*/
chat(char *str)
{
PCstr tmpstr[257];
CtoPCstrcpy(tmpstr, str);
stattext(P(tmpstr), 0);
}
/* returns NA_ALLCLOSED if appropriate, else NA_CLOSED
*/
static short alldone(na_win *win)
{
if (win->next == NULL && win->afterp == NULL && (*mpack_prefs)->quit_finished
&& RecoverHandle((Ptr) win) == (Handle) NAhead) {
return (NA_ALLCLOSED);
}
return (NA_CLOSED);
}
/* update procedure for status dialog box
*/
static short statupdate(na_win *win, Boolean newsize)
{
RgnHandle savergn;
unsigned char *s;
short row, top;
Rect tmpr;
FrameRect(&swin->frect);
savergn = NewRgn();
if (savergn) {
GetClip(savergn);
SetClip(swin->urgn);
}
/* redraw text area */
HLock(swin->text);
s = * (unsigned char **) swin->text;
top = swin->urect.top;
for (row = 0; row < swin->row; ++row) {
s += s[1] + 2;
}
for (; row < swin->nrow && top + swin->height <= swin->urect.bottom; ++row) {
MoveTo(swin->urect.left, top + swin->ascent);
if (*s) TextFace(1);
DrawString(s + 1);
if (*s) TextFace(0);
/* advance to next string */
top += swin->height;
s += s[1] + 2;
}
HUnlock(swin->text);
if (savergn) {
SetClip(savergn);
DisposeRgn(savergn);
}
return (NA_NOTPROCESSED);
}
/* refresh status window
*/
void statrefresh()
{
na_win *win = curstatwin;
Draw1Control(swin->sb);
statupdate(win, false);
}
/* add text to the status window
*/
void stattext(Str255 str, unsigned char bold)
{
na_win *win = curstatwin;
short i, len;
unsigned char *s, *start;
RgnHandle rgn;
Rect tmpr;
if (!win) return;
didchat = 1;
/* advance to next row */
if (swin->height * (swin->nrow++ - swin->row)
>= swin->urect.bottom - swin->urect.top) {
SetCtlMax(swin->sb, ++swin->row);
SetCtlValue(swin->sb, swin->row);
if ((rgn = NewRgn()) != NULL) {
tmpr = swin->urect;
ScrollRect(&tmpr, 0, -swin->height, rgn);
DisposeRgn(rgn);
}
}
/* add the text */
len = * (unsigned char *) str;
if (swin->size - swin->used < len + 1) {
SetHandleSize(swin->text, swin->size * 2);
if (MemError() == 0) swin->size *= 2;
}
HLock(swin->text);
s = start = * (unsigned char **) swin->text;
for (i = 1; i < swin->nrow; ++i) {
s += s[1] + 2;
}
if (len + 2 + s < start + swin->size) {
*s = bold;
memcpy(s + 1, str, len + 1);
swin->used = s + len + 2 - start;
}
HUnlock(swin->text);
statupdate(win, false);
}
/* scroll the status dialog
*/
static void statscroll(na_win *win, short rows)
{
RgnHandle rgn;
if ((rgn = NewRgn()) != NULL) {
SetCtlValue(swin->sb, swin->row += rows);
ScrollRect(&swin->urect, 0, - swin->height * rows, rgn);
EraseRgn(rgn);
DisposeRgn(rgn);
}
statupdate(win, false);
}
/* scroll bar procedure
*/
static pascal void statscollbar(ControlHandle ctrlh, short part)
{
na_win *win = (na_win *) GetCRefCon(ctrlh);
short max, new, page;
max = GetCtlMax(ctrlh);
page = (swin->urect.bottom - swin->urect.top) / swin->height - 1;
switch (part) {
case inUpButton:
page = 1;
/* fall through */
case inPageUp:
if (swin->row > 0) {
statscroll(win, - (swin->row < page ? swin->row : page));
}
break;
case inDownButton:
page = 1;
/* fall through */
case inPageDown:
if (swin->row < max) {
statscroll(win, max - swin->row < page ? max - swin->row : page);
}
break;
case inThumb:
break;
}
}
/* control procedure for status dialog box
*/
static short statctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
{
short value;
if (ctrlh == swin->sb) {
ctrlh = swin->sb;
if (item != inThumb) {
SetCRefCon(ctrlh, (long) win);
TrackControl(ctrlh, p, statscollbar);
} else {
TrackControl(ctrlh, p, nil);
value = GetCtlValue(ctrlh);
if (value != swin->row) statscroll(win, value - swin->row);
}
} else if (item == iOk) {
return (NA_REQCLOSE);
}
return (NA_NOTPROCESSED);
}
/* close procedure for status dialog box
*/
static short statclose(na_win *win)
{
DisposeRgn(swin->urgn);
DisposHandle(swin->text);
DisposeControl(swin->sb);
return (alldone(win));
}
/* init procedure for status dialog box
*/
static short statinit(na_win *win, long *data)
{
Rect tmpr;
FontInfo finfo;
/* disable OK button while working */
NAhiliteDItem(win->pwin, iOk, 255);
/* set up status text area & font */
if ((swin->urgn = NewRgn()) == NULL) return (NA_CLOSED);
TextFont(geneva);
TextSize(9);
GetFontInfo(&finfo);
swin->ascent = finfo.ascent;
swin->height = finfo.ascent + finfo.descent + finfo.leading;
NAgetDRect(win->pwin, iStatus, &swin->frect);
swin->urect = swin->frect;
InsetRect(&swin->urect, 2,
2 + ((swin->urect.bottom - swin->urect.top - 4) % swin->height) / 2);
RectRgn(swin->urgn, &swin->urect);
/* set up text storage */
if ((swin->text = NewHandle(swin->size = 1024)) == NULL) {
DisposeRgn(swin->urgn);
return (NA_CLOSED);
}
**(char **)swin->text = '\0';
/* set up scrollbar */
NAgetDRect(win->pwin, iStatScroll, &tmpr);
swin->sb = NewControl(win->pwin, &tmpr, "\p", true, 0, 0, 0, scrollBarProc, 0);
if (!swin->sb) {
DisposeRgn(swin->urgn);
DisposHandle(swin->text);
return (NA_CLOSED);
}
/* set up procedures */
win->closep = statclose;
win->ctrlp = statctrl;
win->updatep = statupdate;
/* keep window locked until decoding is done */
++win->locks;
curstatwin = win;
return (NA_NOTPROCESSED);
}
/* process the files in the file list
*/
static void do_decodefiles(na_win *win)
{
int count = dwin->count;
filelist *fl;
FILE *dfile, *tmpf;
extern long _ftype, _fcreator;
long ticks;
int result;
MapTypeCreator("text/plain", 0);
SetCursor(&watch);
if (NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_DEFBUTTON | NA_USERESOURCE
| NA_CLOSEBOX | NA_HASCONTROLS,
0, dstatDLOG, 0, sizeof (statuswin), statinit) == NA_CLOSED) {
warn("Not enough memory to decode");
return;
}
MoveHHi((Handle) dwin->hflist);
HLock((Handle) dwin->hflist);
fl = *dwin->hflist;
tmpf = tmpfile();
while (count--) {
stattext(fl->fname, 1);
didchat = 0;
if (dfile = Macopen(tmpf, fl->fname, fl->vRefNum, fl->dirID, 0, 0, 1)) {
result = handleMessage(part_init(dfile), "text/plain",
0, (*mpack_prefs)->extract_text);
if (result != 0 || didchat <= 0) {
if (didchat < 0) {
chat("Decoding cancelled");
} else {
chat("Found nothing to decode");
}
}
fclose(dfile);
} else {
chat("Couldn't find source file");
}
++fl;
}
fclose(tmpf);
HUnlock((Handle) dwin->hflist);
NAhiliteDItem(curstatwin->pwin, iOk, 0);
NAunlockWindow(curstatwin);
curstatwin = NULL;
SetCursor(&arrow);
DisposHandle((Handle) dwin->hflist);
}
/* return non-zero if two filenames have the same prefix
*/
static int fprefixMatch(char *base, PCstr *match)
{
PCstr temp[257];
char *scan;
short prefixlen;
PtoPCstrcpy(temp, base);
scan = C(temp) + PCstrlen(temp) - 1;
while (isdigit(*scan) && scan > C(temp)) --scan;
prefixlen = scan - C(temp) + 1;
if (strncmp(C(temp), C(match), prefixlen)) return (0);
scan = C(match) + prefixlen;
while (isdigit(*scan)) ++scan;
return (!*scan);
}
/* do the add of a file to a list
*/
static void addit(listwin *dw, short vRefNum, long dirID, char *fname)
{
long size = GetHandleSize((Handle) dw->hflist) / sizeof (filelist);
filelist *fl;
char *bp;
Cell c;
int i;
PCstr fbuf[42];
if (size == dw->count) {
SetHandleSize((Handle) dw->hflist, (++size * sizeof (filelist)));
if (MemError() != noErr) return;
}
MoveHHi((Handle) dw->hflist);
HLock((Handle) dw->hflist);
fl = *dw->hflist;
for (i = dw->count; i; --i, ++fl) {
if (fl->vRefNum == vRefNum && fl->dirID == dirID &&
*fl->fname == *fname && !strncmp(C(fl->fname), C(fname), *fl->fname)) {
break;
}
}
if (!i) {
fl->vRefNum = vRefNum;
fl->dirID = dirID;
PtoPCstrcpy(fl->fname, fname);
SetPt(&c, 0, dw->count);
LAddRow(1, ++dw->count, dw->l);
LSetCell((Ptr) C(fname), (short) Pstrlen(fname), c, dw->l);
}
HUnlock((Handle) dw->hflist);
}
/* add file set to file list
*/
static void addfile(dw, fspec)
listwin *dw;
FSSpec *fspec;
{
CInfoPBRec cipbr;
HFileInfo *fpb = (HFileInfo *)&cipbr;
PCstr fbuf[42];
short idx, foundone = 0;
long procid;
/* remove working directory stuff */
if (fspec->parID == 0) {
GetWDInfo(fspec->vRefNum, &fspec->vRefNum, &fspec->parID, &procid);
}
/* loop through directory */
for (idx = 1; ; ++idx) {
fpb->ioVRefNum = fspec->vRefNum;
fpb->ioNamePtr = P(fbuf);
fpb->ioDirID = fspec->parID;
fpb->ioFDirIndex = idx;
if (PBGetCatInfoSync(&cipbr)) break;
SetClen(fbuf);
if (!(fpb->ioFlAttrib & 16) && fprefixMatch((char *)fspec->name, fbuf)) {
addit(dw, fspec->vRefNum, fspec->parID, (char *) P(fbuf));
foundone = 1;
}
}
if (!foundone) {
addit(dw, fspec->vRefNum, fspec->parID, (char *) fspec->name);
}
}
/* remove file from file list
*/
static void removefile(dw)
listwin *dw;
{
filelist *fl;
int count;
Cell c;
c.h = c.v = 0;
if (LGetSelect(TRUE, &c, dw->l)) {
MoveHHi((Handle) dw->hflist);
HLock((Handle) dw->hflist);
fl = *dw->hflist + c.v;
count = dw->count - c.v;
while (--count) {
fl[0] = fl[1];
++fl;
}
HUnlock((Handle) dw->hflist);
--dw->count;
LDelRow(1, c.v, dw->l);
}
}
/* close list window
*/
static short listclose(win)
na_win *win;
{
LDispose(dwin->l);
return (alldone(win));
}
/* mouse procedure
*/
static short listmouse(na_win *win, Point p, short type, short mods)
{
Cell c;
if (!(type & 1)) {
LClick(p, mods, dwin->l);
c.h = c.v = 0;
NAhiliteDItem((DialogPtr)win->pwin, iRemove, LGetSelect(TRUE, &c, dwin->l) ? 0 : 255);
}
return (NA_NOTPROCESSED);
}
/* control procedure
*/
static short listctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
{
StandardFileReply reply;
switch (item) {
case iAdd:
NAgetFile(NULL, 1, textList, &reply);
if (reply.sfGood) {
if (!dwin->count) {
NAhiliteDItem((DialogPtr)win->pwin, iOk, 0);
}
addfile(dwin, &reply.sfFile);
}
return (NA_PROCESSED);
case iRemove:
removefile(dwin);
NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
if (!dwin->count) {
NAhiliteDItem((DialogPtr)win->pwin, iOk, 255);
}
return (NA_PROCESSED);
case iOk:
win->afterp = do_decodefiles;
case iCancel:
return (NA_REQCLOSE);
}
return (NA_NOTPROCESSED);
}
/* update the list window
*/
static short listupdate(na_win *win, Boolean resize)
{
Rect r;
NAgetDRect(win->pwin, iFileList, &r);
FrameRect(&r);
LUpdate(win->pwin->visRgn, dwin->l);
return (NA_NOTPROCESSED);
}
/* initialize the list window
*/
static short listinit(win, data)
na_win *win;
long *data;
{
FSSpec *fspec = (FSSpec *) data;
Rect r, zrect;
Point p;
Handle hand;
short type;
GetDItem((DialogPtr)win->pwin, iFileList, &type, &hand, &r);
InsetRect(&r, 1, 1);
zrect.top = zrect.bottom = zrect.left = p.h = p.v = 0;\
zrect.right = 1;
dwin->l = LNew(&r, &zrect, p, 0, win->pwin, 0, 0, 0, 1);
if (!dwin->l) return (NA_CLOSED);
(*dwin->l)->selFlags = lOnlyOne;
dwin->hflist = (filelist **) NewHandle(sizeof (filelist));
if (!dwin->hflist) {
LDispose(dwin->l);
return (NA_CLOSED);
}
dwin->count = 0;
addfile(dwin, fspec);
win->closep = listclose;
win->updatep = listupdate;
win->ctrlp = listctrl;
win->mousep = listmouse;
win->type = DECODELIST;
NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
ShowWindow(win->pwin);
LDoDraw(TRUE, dwin->l);
return (NA_NOTPROCESSED);
}
/* Decode procedure: first get a file, then open decode window
*/
static void do_decode(FSSpec *fspec)
{
StandardFileReply infile;
na_win **wh, *wp;
if (!fspec) {
NAgetFile(NULL, 1, textList, &infile);
if (!infile.sfGood) return;
fspec = &infile.sfFile;
} else {
/* file supplied by drag & drop, look for existing decode window: */
for (wh = NAhead; wh && (*wh)->type != DECODELIST; wh = (*wh)->next);
if (wh && (wp = NAlockWindow(wh)) != NULL) {
addfile((listwin *) wp, fspec);
NAunlockWindow(wp);
return;
}
}
NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_DEFBUTTON |
NA_HASCONTROLS | NA_CLOSEBOX, NULL, decodeDLOG, (long *) fspec,
sizeof (listwin), listinit);
}
/* Map MIME type to/from Macintosh file types
*/
void MapTypeCreator(char *contenttype, OSType type)
{
extern long _ftype, _fcreator;
PCstr tstr[257];
Handle h;
ICAttr attr;
long size = 0;
Ptr map;
ICMapEntry *ment;
unsigned char *scan, *end, *pstr;
short mapcount, i, foundit = 0;
OSType temp;
if (!type) CtoPCstrncpy(tstr, contenttype, 255);
/* first try a lookup via Internet Config */
if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
if (ICGetPref(icinst, kICMapping, &attr, nil, &size) == noErr
&& size > 0 && (map = NewPtr(size)) != nil) {
if (ICGetPref(icinst, kICMapping, &attr, map, &size) == noErr) {
scan = (unsigned char *) map;
end = scan + size;
while (scan < end) {
ment = (ICMapEntry *) scan;
pstr = scan + ment->fixed_length;
scan += ment->total_length;
if (type && ment->file_type != type) continue;
pstr += *pstr + 1; /* skip over extension */
pstr += *pstr + 1; /* skip over creator app name */
pstr += *pstr + 1; /* skip over post app name */
if (type) {
PtoPCstrcpy((PCstr *) contenttype, (char *) pstr);
foundit = 1;
break;
} else if (EqualString(P(tstr), pstr, false, true)) {
_ftype = ment->file_type;
_fcreator = ment->file_creator;
foundit = 1;
break;
}
}
}
DisposPtr(map);
}
ICEnd(icinst);
}
/* if we didn't find it, try our quick&dirty mappings */
if (!foundit) {
if (type) {
mapcount = CountResources('TyCr');
for (i = 1; i <= mapcount; ++i) {
h = GetIndResource('TyCr', i);
if (h && **(OSType **)h == type) {
GetResInfo(h, &i, &temp, P(contenttype));
if (ResError() == noErr) break;
}
}
SetClen((PCstr *) contenttype);
} else {
h = GetNamedResource('TyCr', P(tstr));
if (h) {
_ftype = (*(OSType **)h)[0];
_fcreator = (*(OSType **)h)[1];
} else {
_ftype = '????';
_fcreator = 'mPAK';
}
}
}
}
/* get internet config string prefs
*/
static short getICprefs(na_win *win, PCstr *eaddr, PCstr *smtphost)
{
char *scan, *end;
ICAttr attr;
long size;
ICError err = noErr;
*C(eaddr) = '\0';
SetPlen(eaddr);
*C(smtphost) = '\0';
SetPlen(smtphost);
if (icinst && ICBegin(icinst, icReadOnlyPerm) == noErr) {
size = 256;
if (ICGetPref(icinst, kICEmail, &attr, (Ptr) eaddr, &size) == noErr
&& win && (attr & ICattr_locked_mask)) {
NAenableDItem(win->pwin, iEmailAddr, 0);
}
SetClen(eaddr);
size = 256;
if (ICGetPref(icinst, kICSMTPHost, &attr, (Ptr) smtphost, &size) == noErr
&& win && (attr & ICattr_locked_mask)) {
NAenableDItem(win->pwin, iMailServer, 0);
}
SetClen(smtphost);
ICEnd(icinst);
} else {
HLock((Handle) mpack_prefs);
end = (char *) (*mpack_prefs) + GetHandleSize((Handle) mpack_prefs);
scan = (*mpack_prefs)->internet_host;
while (scan < end && *scan++);
if (scan < end) CtoPCstrcpy(eaddr, scan);
while (scan < end && *scan++);
if (scan < end) CtoPCstrcpy(smtphost, scan);
HUnlock((Handle) mpack_prefs);
}
}
/* copy desc file, with word-wrap
*/
static short copydesc(FILE *out, TEHandle hTE)
{
char c;
short i, count, word, col, reset;
char **htxt;
count = (*hTE)->teLength;
htxt = (char **) (*hTE)->hText;
for (i = word = col = 0; i < count; ++i) {
c = (*htxt)[i];
reset = i - word == 80 || c == '\r';
if (reset || c == ' ') {
while (word < i) putc((*htxt)[word], out), ++word;
}
if (reset || ++col == 80) {
putc('\r', out);
c = (*htxt)[word];
if (c == ' ' || c == '\r') ++word;
col = 0;
}
}
while (word < i) putc((*htxt)[word], out), ++word;
rewind(out);
}
/* start up MacTCP callback
*/
static void mytcpinit(short status)
{
static DialogPtr dialog = NULL;
GrafPtr save;
Rect box;
if (status < 0) {
tcpstart = -1;
} else if (status == 0) {
tcpstart = 1;
} else {
if (!dialog && status < 100) {
dialog = GetNewDialog(progDLOG, nil, (WindowPtr) -1);
NAsetIText(dialog, iWorkText, "\pWaiting for MacTCP to finish. Press \021. to stop.");
}
if (dialog) {
GetPort(&save);
SetPort(dialog);
NAgetDRect(dialog, iProgress, &box);
FrameRect(&box);
InsetRect(&box, 1, 1);
box.right = box.left + (box.right - box.left) * status / 100;
FillRect(&box, qd.dkGray);
SetPort(save);
if (status == 100) {
DisposDialog(dialog);
dialog = NULL;
}
}
}
}
/* update the progress bar
*/
static short progressupdate(na_win *win, Boolean newsize)
{
Rect box;
if (prwin->percent >= 0) {
NAgetDRect(win->pwin, iProgress, &box);
FrameRect(&box);
InsetRect(&box, 1, 1);
if (prwin->percent) {
box.right = box.left + (box.right - box.left) * prwin->percent / 100;
FillRect(&box, qd.dkGray);
} else {
EraseRect(&box);
}
}
return (NA_NOTPROCESSED);
}
/* handle the cancel button
*/
static short progressctrl(na_win *win, Point p, short item, short mods,
ControlHandle ctrlh)
{
return (item == iCancel ? NA_REQCLOSE : NA_NOTPROCESSED);
}
/* close progress window
*/
static short progressclose(na_win *win)
{
NAmodalMenus(0);
return (NA_CLOSED);
}
/* make/go directory under prefs and return directory number
*/
static OSErr prefsubdir(PCstr *name, long *dirID)
{
CInfoPBRec cipbr;
DirInfo *dpb = &cipbr.dirInfo;
long subdir, dir;
short vref = pfolder->fspec.vRefNum;
OSErr err;
err = DirCreate(vref, dir = pfolder->fspec.parID, P(name), &subdir);
if (err == dupFNErr) {
dpb->ioVRefNum = vref;
dpb->ioNamePtr = P(name);
dpb->ioDrDirID = dir;
dpb->ioFDirIndex = 0;
if ((err = PBGetCatInfoSync(&cipbr)) != noErr) return (err);
subdir = dpb->ioDrDirID;
} else if (err != noErr) {
return (err);
}
*dirID = subdir;
return (noErr);
}
/* smtp status task
*/
static void smtpstat(void *wh, short code, short err, long num, char *errstr)
{
na_win *win, **winh;
char msg[256];
OSErr oserr = noErr;
/* verify win is valid */
for (winh = NAhead; winh && winh != wh; winh = (*winh)->next);
if (!winh) return;
/* handle SMTP callback */
win = NAlockWindow((na_win **) wh);
if (code == NASMTP_progress) {
prwin->percent = err;
progressupdate(win, false);
} else if (code == NASMTP_badaddr) {
sprintf(msg, "Invalid address: <%s>. Email will be sent to valid recipients.",
errstr);
yell(msg);
} else {
switch (code) {
case NASMTP_nomem:
yell("Not enough memory to send email");
break;
case NASMTP_tcpfail:
yell("Failed to connect to mail host");
break;
case NASMTP_temperr:
case NASMTP_permerr:
sprintf(msg, "Delivery failed: %s", errstr);
yell(msg);
break;
default:
yell("Mail delivery failed.");
case NASMTP_completed:
break;
}
mwin->sending = false;
oserr = HDelete(mwin->fspec.vRefNum, mwin->fspec.parID, mwin->fspec.name);
}
if (oserr != noErr && oserr != fnfErr) {
if (mwin->remaining) ++mwin->cpb.hFileInfo.ioFDirIndex;
yell("Unable to remove temporary email file.");
}
NAunlockWindowh((na_win **) wh, win);
}
/* Get the email hostname
*/
static void mailhost(void *user, na_tcp s, short status, long size, char *data)
{
struct mpack_preferences *mp;
char *ihost;
na_win *win, **winh;
long len, oldsize;
/* first make sure our window still exists */
for (winh = NAhead; winh && winh != user; winh = (*winh)->next);
if (!winh) return;
win = NAlockWindow(winh);
/* check for errors */
if (status != NATCP_connect) {
warn("Failed to get hostname from MacTCP");
} else {
mwin->gothost = true;
if (data[size - 1] == '.') --size;
/* update internet_host preference */
len = strlen((*mpack_prefs)->internet_host);
oldsize = GetHandleSize((Handle) mpack_prefs);
if (len < size) {
SetHandleSize((Handle) mpack_prefs, oldsize + (size - len));
if (MemError() != noErr) return;
}
HLock((Handle) mpack_prefs);
mp = *mpack_prefs;
ihost = mp->internet_host;
memmove(ihost + size + 1, ihost + len + 1,
oldsize - len - 1 - ((char *) ihost - (char *) mp));
memcpy(ihost, data, size);
ihost[size] = '\0';
HUnlock((Handle) mpack_prefs);
}
NAunlockWindowh(winh, win);
}
/* clean up mail task
*/
static short mailclose(na_win *win)
{
if (mwin->dfile != NULL) fclose(mwin->dfile);
if (mwin->envelope) DisposeHandle(mwin->envelope);
if (mwin->headers) DisposeHandle(mwin->headers);
NAmodalMenus(0);
return (alldone(win));
}
/* send email
*/
static short mailtask(na_win *win)
{
short vrefnum, encoding, refnum, result;
long procid;
FILE *tmpf, *fp, *resfork;
OSErr err;
CInfoPBRec cipbr;
HFileInfo *fpb = (HFileInfo *)&cipbr;
PCstr tstr[257], mtype[257], fname[257];
extern long _ftype, _fcreator;
switch (mwin->state) {
case MS_MACTCP:
if (tcpstart < 0) {
yell("Couldn't find MacTCP");
return (NA_REQCLOSE);
}
if (tcpstart == 0) break;
++mwin->state;
NAsetIText(win->pwin, iWorkText, "\pGetting Hostname");
mwin->gothost = false;
NATCPgethost(mailhost, (void *) GetWRefCon(win->pwin));
/* fall through */
case MS_GETHOST:
if (!mwin->gothost) break;
++mwin->state;
/* fall through */
case MS_ENCODE:
NAsetIText(win->pwin, iWorkText, "\pEncoding file");
/* get temp output filename for email */
if (mwin->useemail) {
mwin->ofile.vRefNum = pfolder->fspec.vRefNum;
memcpy(mwin->ofile.name, "\pemail", 6);
if (prefsubdir("\poutgoing-email", &mwin->ofile.parID) != noErr) {
yell("Failed to write encoded file");
return (NA_REQCLOSE);
}
}
/* set file type */
SetCursor(&watch);
MapTypeCreator((char *) mtype, mwin->ftype);
/* Determine the correct encoding */
encoding = (*mpack_prefs)->encoding;
fpb->ioVRefNum = mwin->fspec.vRefNum;
fpb->ioNamePtr = mwin->fspec.name;
fpb->ioDirID = mwin->fspec.parID;
fpb->ioFDirIndex = 0;
if (PBGetCatInfoSync(&cipbr) != noErr) {
SetCursor(&arrow);
yell("File disappeared before being encoded!");
return (NA_REQCLOSE);
}
if (encoding == EN_AUTO) {
encoding = EN_DOUBLE;
if (!fpb->ioFlRLgLen && *mtype != '\0') encoding = EN_DATA;
}
if (!fpb->ioFlLgLen) encoding = EN_SINGLE;
/* do applesingle/appledouble encoding */
tmpf = tmpfile();
fp = Macopen(tmpf, mwin->fspec.name, mwin->fspec.vRefNum, mwin->fspec.parID,
strcmp(C(mtype), "text/plain") ? 1 : 0, 0, fsRdPerm);
if (!fp) {
fclose(tmpf);
SetCursor(&arrow);
yell("Couldn't save encoded file");
return (NA_REQCLOSE);
}
if (encoding == EN_DATA) {
fclose(tmpf);
tmpf = NULL;
} else {
/* open resource fork & output file for applesingle/double encoding */
resfork = Macopen(tmpf, mwin->fspec.name, mwin->fspec.vRefNum,
mwin->fspec.parID, 1, 1, 1);
if (encode_applefile(tmpf, fpb, resfork, encoding == EN_SINGLE ? fp : NULL) < 0) {
SetCursor(&arrow);
yell("Couldn't save encoded file");
return (NA_REQCLOSE);
}
rewind(tmpf);
if (encoding == EN_SINGLE) {
fp = tmpf;
tmpf = NULL;
strcpy(C(mtype), "application/applefile");
SetPlen(mtype);
}
}
/* generate output files */
_fcreator = 'mPAK';
_ftype = 'TEXT';
GetVol(0, &vrefnum);
err = OpenWD(mwin->ofile.vRefNum, mwin->ofile.parID, 0, &refnum);
SetVol(0, err == noErr ? refnum : mwin->ofile.vRefNum);
PtoPCstrcpy(tstr, (char *) mwin->ofile.name);
PtoPCstrcpy(fname, (char *) mwin->fspec.name);
result = encode(fp, tmpf, C(fname), mwin->dfile, C(mwin->subj), NULL,
mwin->partsize, PCstrlen(mtype) ? C(mtype) : NULL, C(tstr));
if (err == noErr) CloseWD(refnum);
SetVol(0, vrefnum);
if (tmpf) fclose(tmpf);
fclose(fp);
if (mwin->dfile) {
fclose(mwin->dfile);
mwin->dfile = NULL;
}
SetCursor(&arrow);
if (!mwin->useemail) return (NA_REQCLOSE);
prwin->percent = 0;
progressupdate(win, false);
++mwin->state;
/* count files */
mwin->cpb.dirInfo.ioVRefNum = mwin->ofile.vRefNum;
mwin->cpb.dirInfo.ioDrDirID = mwin->dirID = mwin->ofile.parID;
mwin->cpb.dirInfo.ioFDirIndex = -1;
if (PBGetCatInfoSync(&mwin->cpb) != noErr) {
return (NA_CLOSED);
}
mwin->remaining = mwin->cpb.dirInfo.ioDrNmFls;
mwin->cpb.dirInfo.ioFDirIndex = 1;
/* fall through */
case MS_SENDING:
if (mwin->sending) break;
if (!mwin->remaining) return (NA_REQCLOSE);
sprintf(C(tstr), "Email parts remaining to submit: %d", mwin->remaining--);
SetPlen(tstr);
NAsetIText(win->pwin, iWorkText, tstr);
prwin->percent = 0;
progressupdate(win, false);
mwin->cpb.hFileInfo.ioDirID = mwin->dirID;
mwin->cpb.hFileInfo.ioNamePtr = (StringPtr) &mwin->fspec.name;
if (PBGetCatInfoSync(&mwin->cpb) != noErr) {
yell("Email disappeared before submission!");
return (NA_REQCLOSE);
}
mwin->sending = true;
mwin->fspec.vRefNum = mwin->cpb.hFileInfo.ioVRefNum;
mwin->fspec.parID = mwin->dirID;
NASMTPsubmit(smtpstat, C(mwin->server), &mwin->fspec,
mwin->headers, mwin->envelope,
NASMTP_crtrans, (void *) GetWRefCon(win->pwin));
break;
}
return (NA_NOTPROCESSED);
}
/* Following routine stolen from Mark Crispin's c-client library:
*
* Write current time in RFC 822 format
* Accepts: destination string
*
* This depends upon the ReadLocation() call in System 7 and the
* user properly setting his location/timezone in the Map control
* panel.
* 2/95 - I added support for dlsDelta & compatibility checking
*/
void rfc822_date(char *string)
{
long tz, tzm;
time_t ti = time (0);
struct tm *t = localtime (&ti);
MachineLocation loc;
/* output date */
strcpy(string, "Date: ");
string += 6;
strftime (string,1024,"%a, %d %b %Y %H:%M:%S ",t);
/* now output time zone, if we can get it */
tz = 0;
if (Gestalt(gestaltScriptMgrVersion, &tz) == noErr && tz >= 200) {
ReadLocation(&loc); /* get location/timezone */
/* get sign-extended time zone */
tz = (loc.gmtFlags.gmtDelta & 0x00ffffff) |
((loc.gmtFlags.gmtDelta & 0x00800000) ? 0xff000000 : 0);
tz /= 60; /* get timezone in minutes */
tzm = tz % 60; /* get minutes from the hour */
sprintf (string += strlen(string),"%+03ld%02ld",
tz/60,tzm >= 0 ? tzm : -tzm);
if (!tzm && tz <= -240 && tz >= -660) {
string += strlen(string);
if (loc.gmtFlags.dlsDelta & 0x80) {
sprintf(string, " (%cDT)", "AECMPYHB"[- (tz / 60) - 3]);
} else {
sprintf(string, " (%cST)", "AECMPYHB"[- (tz / 60) - 4]);
}
}
} else {
sprintf(string + strlen(string), "+0000 (Local Time Zone Unknown)");
}
}
/* init mail sending
*/
static short mailinit(na_win *win, long *data)
{
encodewin *ew = (encodewin *) data;
WindowPtr pwin = ew->w.winp.pwin;
ControlHandle ctrlh;
PCstr tstr[257], email[257];
/* copy values from encode window */
NAgetIText(pwin, iSubj, mwin->subj);
NAgetIText(pwin, iEmailto, email);
mwin->partsize = ew->partsize;
mwin->useemail = ew->useemail;
mwin->fspec = ew->fspec;
mwin->ftype = ew->ftype;
mwin->ofile = ew->ofile;
/* copy desc file */
mwin->dfile = NULL;
if ((*ew->w.hTE)->teLength && (mwin->dfile = tmpfile()) != NULL) {
copydesc(mwin->dfile, ew->w.hTE);
}
/* set procedures */
win->taskp = mailtask;
win->updatep = progressupdate;
win->ctrlp = progressctrl;
win->closep = mailclose;
/* Customize Progress window, set up envelope & headers for email */
prwin->percent = -1;
NAgetDHandle(win->pwin, iCancel, &ctrlh);
SetCTitle(ctrlh, "\pStop");
NAmodalMenus(1);
if (!mwin->useemail) {
mwin->state = MS_ENCODE;
} else {
if (!tcpstart) NATCPinit(mytcpinit);
NAsetIText(win->pwin, iWorkText, "\pLooking for MacTCP");
mwin->state = MS_MACTCP;
/* create envelope, get server */
getICprefs(NULL, tstr, mwin->server);
if (PtrToHand(C(tstr), &mwin->envelope, PCstrlen(tstr) + 1) != noErr
|| PtrAndHand(C(email), mwin->envelope, PCstrlen(email) + 1) != noErr) {
if (mwin->envelope) DisposeHandle(mwin->envelope);
return (NA_CLOSED);
}
/* create headers */
if ((mwin->headers = NewHandle(1024)) == NULL) {
DisposeHandle(mwin->envelope);
return (NA_CLOSED);
}
HLock(mwin->headers);
rfc822_date((char *) *mwin->headers);
sprintf((char *) (*mwin->headers) + strlen((char *) (*mwin->headers)),
"\r\nFrom: %s\r\nTo: %s\r\n", C(tstr), C(email));
HUnlock(mwin->headers);
SetHandleSize(mwin->headers, strlen((char *) (*mwin->headers)));
}
return (NA_NOTPROCESSED);
}
/* update the encode window
*/
static short encodeupdate(na_win *win, Boolean newsize)
{
Rect btmp;
ControlHandle ctrlh;
/* draw double-line */
NAgetDRect(win->pwin, iBar, &btmp);
FrameRect(&btmp);
/* draw disabled edittext boxes */
NAgetDHandle(win->pwin, iLimit, &ctrlh);
if (!GetCtlValue(ctrlh)) {
NAhiliteDItem(win->pwin, iPartLimit, 255);
}
if (NAradioGet(win->pwin, iEmail, iSavefile) == iSavefile) {
NAhiliteDItem(win->pwin, iEmailto, 255);
}
return (NATEupdatep(win, newsize));
}
/* select desc text
*/
static short seldesctext(na_win *win)
{
win->activep = NATEactivep;
win->idlep = NATEidlep;
NATEactivep(win, true);
ewin->nateon = true;
SelIText(win->pwin, iDescEdit, 0, 0);
TESetSelect(32767, 32767, twin->hTE);
}
/* encode control proc
*/
static short encodectrl(na_win *win, Point p, short item,
short mods, ControlHandle ctrlh)
{
short value;
DialogPeek dpeek = (DialogPeek) win->pwin;
char *scan;
Boolean good;
StandardFileReply reply;
PCstr tstr[257];
if (ctrlh == twin->vctrl) {
return (NATEctrlp(win, p, item, mods, ctrlh));
}
switch (item) {
case iOk:
/* get part size */
ewin->partsize = 0;
NAgetDHandle(win->pwin, iLimit, &ctrlh);
if (GetCtlValue(ctrlh)) {
NAgetIText(win->pwin, iPartLimit, tstr);
ewin->partsize = atol(C(tstr)) * 1000;
}
NAgetIText(win->pwin, iEmailto, tstr);
ewin->useemail = NAradioGet(win->pwin, iEmail, iSavefile) == iEmail;
if (ewin->useemail) {
/* verify email address */
if (!strchr(C(tstr), '@')) {
yell("Invalid Email address, please re-enter");
SelIText(win->pwin, iEmailto, 0, 32767);
break;
}
} else {
/* get output filename */
PtoPCstrcpy(tstr, (char *) ewin->fspec.name);
if (PCstrlen(tstr) > 23) {
PCstrlen(tstr) = 23;
SetClen(tstr);
}
strcat(C(tstr), ".mime");
SetPlen(tstr);
do {
NAputFile(ewin->partsize ? "\pPart prefix" : "\pEmail file:",
tstr, &reply);
good = true;
if (reply.sfGood
&& EqualString(reply.sfFile.name,
ewin->fspec.name, true, false)) {
good = false;
yell("The output filename must be different from the input filename");
}
} while (!good);
if (!reply.sfGood) break;
ewin->ofile = reply.sfFile;
}
if (NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_HASTASK
| NA_USERESOURCE | NA_MODAL, NULL, progDLOG,
(long *) win, sizeof (mailwin), mailinit) == NA_CLOSED) {
warn("Not enough memory to proceed");
break;
}
case iCancel:
return (NA_REQCLOSE);
case iEmail:
case iSavefile:
NAradioSet(win->pwin, iEmail, iSavefile, item);
NAenableDItem(win->pwin, iEmailto, item == iEmail ? 1 : 0);
NAhiliteDItem(win->pwin, iEmailto, item == iEmail ? 0 : 255);
if (item == iEmail || dpeek->editField == iEmailto - 1) {
SelIText(win->pwin, item == iEmail ? iEmailto : iSubj, 0, 32767);
}
break;
case iLimit:
SetCtlValue(ctrlh, value = !GetCtlValue(ctrlh));
NAenableDItem(win->pwin, iPartLimit, value ? 1 : 0);
NAhiliteDItem(win->pwin, iPartLimit, value ? 0 : 255);
if (value || dpeek->editField == iPartLimit - 1) {
SelIText(win->pwin, value ? iPartLimit : iSubj, 0, 32767);
}
break;
case iDescEdit:
case iSubj:
case iEmailto:
case iPartLimit:
if (!ewin->nateon && dpeek->editField == iDescEdit - 1) {
seldesctext(win);
}
break;
}
if (ewin->nateon && dpeek->editField != iDescEdit - 1) {
win->activep = NULL;
win->idlep = NULL;
NATEactivep(win, false);
ewin->nateon = false;
}
return (NA_NOTPROCESSED);
}
/* encode key proc
*/
static short encodekey(na_win *win, long c, short mods)
{
if (!(mods & cmdKey)) {
if (ewin->nateon && c != '\t' && c != '\n' && c != '\3' && c != '\033') {
return (NATEkeyp(win, c, mods));
}
}
return (NA_NOTPROCESSED);
}
/* menu proc for encode window
*/
static short encodemenu(na_win *win, WORD menu, WORD item)
{
StandardFileReply descfile;
MenuHandle mf = NAmenuh(mFile);
short result = NA_NOTPROCESSED;
short refnum;
long size;
Ptr text;
Boolean success;
switch (menu) {
case 0:
EnableItem(mf, iInsert);
/* fall through */
case mEdit:
result = ewin->nateon ? NATEmenup(win, menu, item)
: NAdialogMenu(win, menu, item);
break;
case mFile:
if (item != iInsert) break;
result = NA_PROCESSED;
NAgetFile(NULL, 1, textList, &descfile);
if (!descfile.sfGood) break;
if (HOpen(descfile.sfFile.vRefNum, descfile.sfFile.parID,
descfile.sfFile.name, fsRdPerm, &refnum) != noErr) {
warn("Failed to open file");
break;
}
text = NULL;
success = GetEOF(refnum, &size) == noErr && (text = NewPtr(size)) != NULL
&& FSRead(refnum, &size, text) == noErr;
if (success) {
TEInsert(text, size, twin->hTE);
TESelView(twin->hTE);
NATEsetscroll(win, false, (Rect*) NULL, (Rect*) NULL);
} else {
warn("Failed to read file");
}
if (text) DisposPtr(text);
FSClose(refnum);
break;
}
if (menu != 0) DisableItem(mf, iInsert);
return (result);
}
/* mouse proc for encode window
*/
static short encodemouse(na_win *win, Point p, short type, short mods)
{
if (p.v >= twin->topoff && !ewin->nateon) seldesctext(win);
return (NATEmousep(win, p, type, mods));
}
/* close the encode window
*/
static short encodeclose(na_win *win)
{
NATEclosep(win);
return (NA_CLOSED);
}
/* init the encode window
*/
static short encodeinit(na_win *win, long *data)
{
StandardFileReply *sf = (StandardFileReply *) data;
Rect rtmp, btmp;
FontInfo finfo;
/* copy data */
ewin->fspec = sf->sfFile;
ewin->ftype = sf->sfType;
/* set sizing limits */
NAgetDRect(win->pwin, iBar, &btmp);
rtmp = win->pwin->portRect;
win->minw = win->maxw = rtmp.right - rtmp.left;
win->minh = btmp.bottom + 64;
twin->topoff = btmp.bottom;
/* init text area */
TextFont(monaco);
TextSize(9);
GetFontInfo(&finfo);
NATEinit(win, NATE_NOHSCROLL, 80 * finfo.widMax + 2, NULL, 0);
ewin->nateon = 0;
TextFont(0);
TextSize(0);
/* set control values */
NAradioSet(win->pwin, iEmail, iSavefile, iSavefile);
if (tcpstart < 0) NAhiliteDItem(win->pwin, iEmail, 255);
NAenableDItem(win->pwin, iEmailto, 0);
NAenableDItem(win->pwin, iPartLimit, 0);
NAsetIText(win->pwin, iSubj, ewin->fspec.name);
SelIText(win->pwin, iSubj, 0, 32767);
SetWTitle(win->pwin, ewin->fspec.name);
ShowWindow(win->pwin);
/* set window procedures */
win->updatep = encodeupdate;
win->closep = encodeclose;
win->keyp = encodekey;
win->ctrlp = encodectrl;
win->mousep = encodemouse;
win->menup = encodemenu;
win->idlep = NULL;
win->activep = NULL;
return (NA_NOTPROCESSED);
}
/* Encode procedure: first get a file, then open encode save window
*/
static void do_encode(FSSpec *fspec, OSType ftype)
{
StandardFileReply infile;
if (!fspec) {
NAgetFile(NULL, -1, NULL, &infile);
if (!infile.sfGood) return;
} else {
infile.sfFile = *fspec;
infile.sfType = ftype;
}
NAwindow(NULL, NA_DIALOGWINDOW | NA_TITLEBAR | NA_GROWBOX | NA_USERESOURCE
| NA_DEFBUTTON | NA_HASCONTROLS,
NULL, sendDLOG, (long *) &infile, sizeof (encodewin), encodeinit);
}
/* Open a file via drag&drop
*/
static short openfile(short message, FSSpec *fspec, FInfo *finfo)
{
if (message != appOpen) return (-1);
/* open file */
if (finfo->fdType == 'TEXT') {
do_decode(fspec);
} else {
do_encode(fspec, finfo->fdType);
}
return (0);
}
#define hwinfo ((nate_win *)win)
/* help close procedure
*/
static short helpclose(na_win *win)
{
helpw = NULL;
return (NATEclosep(win));
}
/* help window procedure
*/
static short helpwindow(na_win *win, long *data)
{
Rect rtemp, vtemp;
Handle h, hs;
long len;
TEHandle hTE;
rtemp = win->pwin->portRect;
vtemp = rtemp;
vtemp.right = vtemp.left + (hwinfo->docwidth = 475);
win->mousep = NATEmousep;
win->idlep = NATEidlep;
win->menup = NATEmenup;
win->activep = NATEactivep;
win->updatep = NATEupdatep;
win->ctrlp = NATEctrlp;
win->closep = helpclose;
win->cursorRgn = NewRgn();
hwinfo->vctrl = hwinfo->hctrl = NULL;
TEAutoView(true, hTE = hwinfo->hTE = TEStylNew(&vtemp, &rtemp));
h = GetResource('TEXT', helpTEXT);
hs = GetResource('styl', helpSTYL);
len = GetHandleSize(h);
HLock(h);
TEStylInsert(*h, len, (StScrpHandle) hs, hTE);
HUnlock(h);
TESetSelect(0, 0, hTE);
hwinfo->lheight = TEGetHeight((*hTE)->nLines, 0, hTE) / (*hTE)->nLines;
ShowWindow(helpw = win->pwin);
return (NA_NOTPROCESSED);
}
/* Set the hostname: TCP callback
*/
static void sethost(void *user, na_tcp s, short status, long size, char *data)
{
PCstr host[65];
Rect box;
na_win *win, **winh;
/* first make sure our window still exists */
for (winh = NAhead; winh && (*winh)->type != PREFWIN; winh = (*winh)->next);
if (!winh || (*winh)->child != user) return;
win = NAlockWindow((na_win **) user);
/* check for errors */
if (status != NATCP_connect) {
warn("Failed to get hostname from MacTCP");
} else {
if (data[size - 1] == '.') --size;
PCstrlen(host) = size;
memcpy(C(host), data, size);
NAsetIText((*winh)->pwin, iHost, host);
SelIText((*winh)->pwin, iHost, 0, 32767);
}
prwin->percent = 100;
progressupdate(win, false);
NAunlockWindowh(winh, win);
}
/* if TCP is active, get hostname
*/
static short settask(na_win *win)
{
if (tcpstart == 0 && !prwin->percent) {
NAsetIText(win->pwin, iWorkText, "\pLooking for MacTCP");
prwin->percent = 1;
progressupdate(win, false);
NATCPinit(mytcpinit);
} else if (tcpstart == 1 && prwin->percent < 50) {
NAsetIText(win->pwin, iWorkText, "\pLooking up Internet hostname");
prwin->percent = 50;
progressupdate(win, false);
NATCPgethost(sethost, (void *) GetWRefCon(win->pwin));
}
progressupdate(win, false);
if (tcpstart == -1) {
warn("MacTCP not available");
NAhiliteDItem((*win->parent)->pwin, iSet, 255);
}
return (tcpstart == -1 || prwin->percent == 100 ? NA_CLOSED : NA_NOTPROCESSED);
}
/* set the Internet host via MacTCP
*/
static short setinit(na_win *win, long *data)
{
win->taskp = settask;
win->updatep = progressupdate;
win->closep = progressclose;
NAmodalMenus(1);
return (NA_NOTPROCESSED);
}
/* preference control procedure
*/
static short prefsctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
{
PCstr tmpstr[257];
short encoding, extract_text, quit_finished, result = NA_NOTPROCESSED;
ControlHandle ctrl;
char *scan, *end;
short changed, len, i, useic;
static short prefitem[3] = { iHost, iEmailAddr, iMailServer };
switch (item) {
case iOk:
HLock((Handle) mpack_prefs);
changed = 0;
encoding = NAradioGet(win->pwin, iAuto, iDouble) - iAuto;
NAgetDHandle(win->pwin, iTextEncode, &ctrl);
extract_text = GetCtlValue(ctrl);
NAgetDHandle(win->pwin, iQuitFinish, &ctrl);
quit_finished = GetCtlValue(ctrl);
if (encoding != (*mpack_prefs)->encoding
|| extract_text != (*mpack_prefs)->extract_text
|| quit_finished != (*mpack_prefs)->quit_finished) {
changed = 1;
}
if (changed) {
(*mpack_prefs)->encoding = encoding;
(*mpack_prefs)->extract_text = extract_text;
(*mpack_prefs)->quit_finished = quit_finished;
ChangedResource((Handle) mpack_prefs);
changed = 0;
}
len = 1;
scan = (*mpack_prefs)->internet_host;
end = (char *) *mpack_prefs + GetHandleSize((Handle) mpack_prefs);
for (i = 0; i < 3; ++i) {
NAgetIText(win->pwin, prefitem[i], P(tmpstr));
SetClen(tmpstr);
len += PCstrlen(tmpstr);
if (scan == end || strcmp(C(tmpstr), scan)) {
changed = 1;
}
while (scan < end && *scan++);
}
if (changed) {
HUnlock((Handle) mpack_prefs);
/* update the preferences resource */
SetHandleSize((Handle) mpack_prefs, sizeof (struct mpack_preferences)
+ len);
HLock((Handle) mpack_prefs);
scan = (*mpack_prefs)->internet_host;
useic = icinst && ICBegin(icinst, icReadWritePerm) == noErr;
for (i = 0; i < 3; ++i) {
NAgetIText(win->pwin, prefitem[i], P(tmpstr));
SetClen(tmpstr);
strcpy(scan, C(tmpstr));
scan += PCstrlen(tmpstr) + 1;
if (i && useic) {
ICSetPref(icinst, i == 1 ? kICEmail : kICSMTPHost,
ICattr_no_change, (Ptr) P(tmpstr), PCstrlen(tmpstr) + 1);
}
}
if (useic) ICEnd(icinst);
ChangedResource((Handle) mpack_prefs);
}
HUnlock((Handle) mpack_prefs);
case iCancel:
result = NA_REQCLOSE;
NAmodalMenus(0);
break;
case iAuto:
case iData:
case iSingle:
case iDouble:
NAradioSet(win->pwin, iAuto, iDouble, item);
break;
case iTextEncode:
case iQuitFinish:
SetCtlValue(ctrlh, !GetCtlValue(ctrlh));
break;
case iSet:
NAwindow(0, NA_DIALOGWINDOW | NA_TITLEBAR | NA_HASTASK | NA_USERESOURCE
| NA_MODAL | NA_CHILDWINDOW,
NULL, progDLOG, NULL, sizeof (progresswin), setinit);
break;
}
return (result);
}
/* update preferences dialog
*/
static short prefsupdate(na_win *win, Boolean newsize)
{
Handle hn;
Rect box;
short type;
/* draw disabled items */
GetDItem(win->pwin, iEmailAddr, &type, &hn, &box);
if (type == statText) NAhiliteDItem(win->pwin, iEmailAddr, 255);
GetDItem(win->pwin, iMailServer, &type, &hn, &box);
if (type == statText) NAhiliteDItem(win->pwin, iMailServer, 255);
return (NA_NOTPROCESSED);
}
/* initialize preferences dialog
*/
static short prefsinit(na_win *win, long *data)
{
PCstr tmpstr[257], eaddr[257];
ControlHandle ctrl;
win->type = PREFWIN;
win->ctrlp = prefsctrl;
win->menup = NAdialogMenu;
win->updatep = prefsupdate;
HLock((Handle) mpack_prefs);
strcpy(C(tmpstr), (*mpack_prefs)->internet_host);
HUnlock((Handle) mpack_prefs);
SetPlen(tmpstr);
NAsetIText(win->pwin, iHost, P(tmpstr));
SelIText(win->pwin, iHost, 0, 32767);
getICprefs(win, eaddr, tmpstr);
NAsetIText(win->pwin, iEmailAddr, P(eaddr));
NAsetIText(win->pwin, iMailServer, P(tmpstr));
NAradioSet(win->pwin, iAuto, iDouble, (*mpack_prefs)->encoding + iAuto);
NAsetIval(win->pwin, iTextEncode, (*mpack_prefs)->extract_text);
NAsetIval(win->pwin, iQuitFinish, (*mpack_prefs)->quit_finished);
if (tcpstart == -1) NAhiliteDItem(win->pwin, iSet, 255);
NAmodalMenus(1);
ShowWindow(win->pwin);
return (NA_NOTPROCESSED);
}
/* Main menu procedure
*/
static short mainmenu(na_win *win, WORD menuid, WORD itemno)
{
short status = NA_NOTPROCESSED;
MenuHandle mh;
PCstr version[32];
switch (menuid) {
case 0:
NAenableMItem(mApple, iAbout);
return (status);
case mApple:
if (itemno == iAbout) {
CtoPCstrcpy(version, MPACK_VERSION);
ParamText(P(version), NULL, NULL, NULL);
return (NA_NOTPROCESSED);
}
break;
case mFile:
switch (itemno) {
case iEncode:
do_encode(NULL, 0);
status = NA_PROCESSED;
break;
case iDecode:
do_decode(NULL);
status = NA_PROCESSED;
break;
case iClose:
break;
case iPrefs:
status = NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE
| NA_MODAL | NA_DEFBUTTON | NA_TITLEBAR,
NULL, prefsDLOG, (long *) NULL, 0, prefsinit);
break;
case iQuit:
status = NA_REQCLOSEALL;
break;
}
break;
case mEdit:
break;
case mHelp:
if (!helpw) {
NAwindow(0, NA_USERESOURCE | NATEflags | NATE_READONLY | NA_SMARTSIZE,
NULL, helpWIND, (long *) NULL, sizeof (nate_win), helpwindow);
} else {
SelectWindow(helpw);
}
break;
}
NAdisableMItem(mApple, iAbout);
return (status);
}
/* make preferences folder/file
* returns -1 on failure.
*/
static short makepref()
{
Handle hpref = NULL, htmpl;
long dirID;
short vRefNum;
char *scan, *end;
PCstr dname[257];
CInfoPBRec cpb;
DirInfo *dp = &cpb.dirInfo;
ParamBlockRec pb;
VolumeParam *vp = &pb.volumeParam;
FInfo finfo;
static unsigned char pname[] = "\pprefs";
/* set up pref folder storage */
pfolder = (struct pref_folder *) NewPtr(sizeof (struct pref_folder));
if (!pfolder) return (-1);
end = scan = (char *) pfolder->prefs + sizeof (pfolder->prefs) - 1;
*scan = '\0';
/* get pref folder */
if (FindFolder(kOnSystemDisk, kPreferencesFolderType,
kCreateFolder, &vRefNum, &pfolder->fspec.parID) != noErr) {
return (-1);
}
/* create subfolder, if needed */
PtoPCstrcpy(dname, (char *) "\pMpack");
(void) DirCreate(vRefNum, pfolder->fspec.parID, P(dname), &dirID);
/* get mpack prefs folder info */
dp->ioNamePtr = P(dname);
dp->ioVRefNum = vRefNum;
dp->ioFDirIndex = 0;
dp->ioDrDirID = pfolder->fspec.parID;
if (PBGetCatInfoSync(&cpb) != noErr) return (-1);
pfolder->fspec.parID = dirID = dp->ioDrDirID;
pfolder->fspec.vRefNum = vRefNum;
/* generate pathname */
dp->ioFDirIndex = -1;
for (;;) {
*--scan = ':';
if (scan - (char *) pfolder->prefs < 1 + PCstrlen(dname)) return (-1);
scan -= PCstrlen(dname);
memcpy(scan, C(dname), PCstrlen(dname));
if ((dp->ioDrDirID = dp->ioDrParID) == 2) break;
if (PBGetCatInfoSync(&cpb) != noErr) return (-1);
}
vp->ioVolIndex = 0;
vp->ioNamePtr = P(dname);
vp->ioVRefNum = vRefNum;
if (PBGetVInfoSync(&pb) != noErr) return (-1);
*--scan = ':';
if (scan - (char *) pfolder->prefs < 16 + PCstrlen(dname)) return (-1);
PtoPCstrcpy(pfolder->prefs, (char *) P(dname));
CtoPCstrcat(pfolder->prefs, scan);
/* Get/Create preferences file */
HCreateResFile(vRefNum, dirID, pname);
if (ResError() == noErr) {
HGetFInfo(vRefNum, dirID, pname, &finfo);
finfo.fdType = 'pref';
finfo.fdCreator = 'mPAK';
HSetFInfo(vRefNum, dirID, pname, &finfo);
hpref = GetResource('mPRF', prefsID);
DetachResource(hpref);
htmpl = GetResource('TMPL', IDnaID);
DetachResource(htmpl);
}
pfolder->refnum = HOpenResFile(vRefNum, dirID, pname, fsRdWrPerm);
if (pfolder->refnum < 0) return (-1);
if (hpref) {
AddResource(hpref, 'mPRF', prefsID, "\p");
AddResource(htmpl, 'TMPL', IDnaID, "\pIDna");
ReleaseResource(htmpl);
} else {
hpref = GetResource('mPRF', prefsID);
}
if (!hpref) return (-1);
mpack_prefs = (struct mpack_preferences **) hpref;
return (0);
}
/* cleanup shared resources
*/
void maccleanup()
{
if (pfolder) {
CloseResFile(pfolder->refnum);
DisposPtr((Ptr) pfolder);
}
if (icinst) ICStop(icinst);
if (tcpstart == 1) NATCPdone(120); /* give 2 seconds to go away */
}
main()
{
CursHandle cursH;
if (NAinit(128, 2, openfile, mainmenu, 3, 1, 0, iClose) == 0) {
/* set up preferences */
if (makepref() < 0) {
yell("Couldn't create preferences file");
} else {
/* set up internet config */
if (ICStart(&icinst, 'mPAK') == noErr) {
(void) ICFindConfigFile(icinst, 0, NULL);
}
/* save watch cursor */
cursH = GetCursor(watchCursor);
watch = **cursH;
/* enter main loop, cleanup on exit */
NAmainloop();
maccleanup();
}
}
}