Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v03i057: mpack-1.0 - encode and decode MIME format files, Part00/06

90 views
Skip to first unread message

Kevin Braunsdorf

unread,
Sep 24, 1993, 8:57:20 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 57
Archive-name: mpack-1.0/00

[From the README.]

mpack/munpack version 1.0

Mpack and munpack are utilities for encoding and decoding (respectively)
binary files in MIME (Multipurpose Internet Mail Extensions) format mail
messages. For compabibility with older forms of transferring binary files,
the munpack program can also decode messages in split-uuencoded format.

Versions are included for unix, pc, and mac systems.

This MIME implementation is intended to be as simple and portable as
possible. For a slightly more sophisticated MIME implementation, see the
program MetaMail, available via anonymous FTP to thumper.bellcore.com, in
directory pub/nsb.

[Reviews]

Platfroms:
Sun4 SUNOS 4.1.3, gcc 2.3.3
SGI Indigo IRIX 4.0.5H
SGI indigo running IRIX 4.0.5F
Sun-4 SunOS 4.1.3
Sun-4 SunOS 5.2
OS/2 gcc/2
SCO Unix 3.2v4.1 on a i386/33 (gcc)
Mips RISCos 4.5X and 5.x
[Others]

Maybe:
DEC Alpha OSF/1 1.3
HP 9000/720 HP-UX 9.0.1
DEC 5100 ULTRIX 4.3
SGI Onyx IRIX 5.0.1

Clues:
[SCO]

To link on SCO you need to include -lsocket on the link to get the
gethostname function.

It runs fine as long as you are saving it to a file. If you want to
have it actually send the mail directly then you need to add the patch
included below. (P#1) [Applied by author. rm'd --Mod.]

[??]
A few things should be fixed before this package is posted, but they
don't warrant another review cycle:

unixpk.c:151: warning: pointer given for argument 2 of `strchr'

getenv isn't declared, so I get:
unixpk.c:56: warning: assignment of pointer from integer lacks a cast
unixpk.c:157: warning: integer given for argument 2 of `strcpy'
...
unixos.c: In function `os_idtodir':
unixos.c:70: warning: integer given for argument 2 of `strcpy'
unixos.c:76: warning: integer given for argument 2 of `strcat'
try including stdlib.h to get a getenv declaration.

[MIPS]
getenv is not declared char * anywhere, and breaks

#include <ctype.h> imissing from one of the files
where issapce is used

Gripes:
The program compiled without errors although there are some warnings
about things not being cast from int's to pointer's.

I'm not a big mime user, but in the limited testing I did, mpack seems
to work fine.

Suggested: [All fixed -- Mod.]
The Unix Makefile sets CFLAGS to `-g' by default; most users would
probably prefer `-O'.

A 'clean' target in the Makefile would be nice.

Compiling with 'gcc -Wall' yields screeds of warnings; they may or
may not be worth fixing.


Comments:
`good results thus far'

`post it after a patch'

`post it'

[The author sent in a version to address some of the points in the
review. I'm posting that one. --Mod.]

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:24:58 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 58
Archive-name: mpack-1.0/01

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:
# "End of part 1 (of 6)."
# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'
if test -f 'mpack-1.0/macnapp.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macnapp.c'\"
else
echo shar: Extracting \"'mpack-1.0/macnapp.c'\" \(39363 bytes\)
cat >'mpack-1.0/macnapp.c' <<'END_OF_FILE'
/* macnapp.c -- macintosh nifty application library
*
* (C) Copyright 1990-1993 by Christopher J. Newman
* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.
*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*
* BUGS:
* - should check 32bit mode works.
*/

#ifndef THINK_C
#include <Resources.h>
#include <Dialogs.h>
#include <Desk.h>
#include <SegLoad.h>
#include <OSEvents.h>
#include <DiskInit.h>
#include <Traps.h>
#include <ToolUtils.h>
#endif
#include <AppleEvents.h>
#include "macnapp.h"

/* export globals */
na_win **NAhead = (na_win**) NULL; /* head of the window tree */
na_win **NAtask = (na_win**) NULL; /* head of the task list */
na_win **NActask = (na_win**) NULL; /* next task to be called */
na_win *NAwin = (na_win*) NULL; /* the current window */
na_menup NAmenup = (na_menup) NULL; /* application menu procedure */
short NAnewitem = 0; /* the new item number */
short NAcloseitem = 0; /* the close item number */
short NAappleitems = 0; /* number of apple menu items */
Boolean NAhasedit = false; /* true if application supports edit menu */
long NAdelay = 30; /* delay (1/60th of a second) between null events */
SysEnvRec NAsysenv; /* set up by Initialize */
Boolean NAinBack = false; /* true when app is in the background */
short NAlastmouse = NA_RELEASE; /* the last mouse event type */
long NAmousetime = 0; /* the time of the last mouse up */
Point NAmousept; /* the point (local) of last mouse down */

THz NAappzone; /* the application heap zone */
RgnHandle NAfullRgn; /* a region containing everything */
RgnHandle NAnullRgn; /* a region containing nothing */
Cursor NAibeam; /* the Ibeam cursor */
long NAgestaltBits; /* flags for gestalt options */

/* private globals */
static Point mselpoint; /* the menu selection point */
static short aestatus; /* if set, close everything */

/* constants for DoDraw procedure */
#define DO_UPDATE 0x0
#define DO_RESIZE 0x1
#define DO_ACTIVATE 0x2
#define DO_DEACTIVATE 0x4

/* private routines */

static na_win **GetWinH(WindowPtr);
static void DoDraw(na_win*, short);
static short DoActivate(WindowPtr, na_win*, Boolean, Point p);
static short DoMenu(na_win*, BYTE);
static void AdjustCursor(na_win*, Point, Boolean);
static short aboutmouse(na_win*, Point, short, short);

/* get the handle to a window
*/
static na_win **GetWinH(window)
WindowPtr window;
{
na_win **winh;

/* make positively sure that we have a valid handle */
if (window != (WindowPtr) NULL && !NAisDAWindow(window)) {
#ifdef DEBUG
if (PtrZone((Ptr) window) == NAappzone && MemError() == noErr) {
#endif
if ((winh = (na_win **) GetWRefCon(window)) != (na_win**) NULL) {
#ifdef DEBUG
if (HandleZone((Handle) winh) == NAappzone && MemError() == noErr) {
if ((*winh)->pwin == window) {
#endif
return (winh);
#ifdef DEBUG
} else {
NAdebug("Corrupted window structure found.\015");
NAdebug("handle: %lx, pwin: %lx, window: %lx\015",
(long) winh, (long) (*winh)->pwin, (long) window);
Debugger();
}
} else {
NAdebug("Corrupted Handle Zone Found.\015");
NAdebug("handle: %lx, error: %ld\015", (long) winh,
(long) MemError());
Debugger();
}
#endif
}
#ifdef DEBUG
} else {
NAdebug("Corrupted Window Pointer Found.\n");
NAdebug("Pointer: %lx, error: %ld\n", (long) window, (long) MemError());
Debugger();
}
#endif
}
return ((na_win**) NULL);
}

/* handle drawing controls & growbox for update/activate events
*/
#ifdef __STDC__
static void DoDraw(na_win *winp, short how)
#else
static void DoDraw(winp, how)
na_win *winp;
short how;
#endif
{
WindowPtr window = winp->pwin;
long flags = winp->flags;

/* hilite or draw controls as appropriate */
if (flags & NA_HASCONTROLS) {
if (how & (DO_ACTIVATE | DO_DEACTIVATE)) {
if (flags & NA_HILITECTRLS) {
ControlHandle ctrl;

for (ctrl = ((WindowPeek) window)->controlList; ctrl;
ctrl = (*ctrl)->nextControl) {
HiliteControl(ctrl, (how & DO_ACTIVATE) ? 0 : 255);
}
}
} else {
DrawControls(window);
}
}

/* draw the grow box properly -- mask out scroll bar outlines */
if (flags & NA_GROWBOX) {
Rect tmpRect;
RgnHandle tmpRgn = window->clipRgn;

tmpRect.left = (tmpRect.right = window->portRect.right) - 15;
tmpRect.top = (tmpRect.bottom = window->portRect.bottom) - 15;
RectRgn(window->clipRgn = NewRgn(), &tmpRect);
DrawGrowIcon(window);
DisposeRgn(window->clipRgn);
window->clipRgn = tmpRgn;
}

/* draw the default button on a dialog */
if (flags & NA_DEFBUTTON) NAdefaultButton(window);

/* calculate the un-cursor region if the window size changed */
if (how & DO_RESIZE) NAcalcCursor(winp);
}

/* handle activate event (either activate or MultiFinder suspend/resume)
*/
#ifdef __STDC__
static short DoActivate(WindowPtr window, na_win *winp, Boolean activate, Point p)
#else
static short DoActivate(window, winp, activate, p)
WindowPtr window;
na_win *winp;
Boolean activate;
Point p;
#endif
{
na_win **winh;
short status = NA_NOTPROCESSED;

/* unlock current front window */
if (winp != (na_win*) NULL) {
NAunlockWindow(winp);
NAwin = (na_win*) NULL;
}

/* check if there is a new window, and lock it */
if (window == (WindowPtr) NULL) return (NA_PROCESSED);

/* for app windows, update the cursor, call the activate proc, and DoDraw */
if ((NAwin = winp = NAlockWindow(winh = GetWinH(window))) != (na_win*) NULL) {
GrafPtr tmpPort;

GetPort(&tmpPort);
SetPort(window);
if (winp->cursorRgn != (RgnHandle) NULL && ((activate && !NAinBack)
|| winp->flags & NA_CURSORON)) {
LocalToGlobal(&p);
AdjustCursor(winp, p, activate);
}
if (winp->activep == (na_activep) NULL
|| (status = (*winp->activep)(winp, activate)) == NA_NOTPROCESSED) {
DoDraw(winp, activate ? DO_ACTIVATE : DO_DEACTIVATE);
}
if (!activate || winp->pwin != FrontWindow()) {
SetPort(tmpPort);
NAunlockWindowh(winh, winp);
NAwin = (na_win*) NULL;
}
}

return (status);
}

/* handle menu selection -- either menu click or menu shortcut
*/
#ifdef __STDC__
static short DoMenu(na_win *winp, BYTE key)
#else
static short DoMenu(winp, key)
na_win *winp;
BYTE key;
#endif
{
WindowPtr window = FrontWindow();
short status = NA_NOTPROCESSED;
WORD menuid, itemno;

/* enable/disable edit menu as appropriate */
if (NAhasedit) {
MenuHandle mnu = GetMHandle(mEdit);

if (NAisDAWindow(window)) {
EnableItem(mnu, iUndo);
for (itemno = iCut; itemno <= iClear; itemno++) {
EnableItem(mnu, itemno);
}
} else {
DisableItem(mnu, iUndo);
for (itemno = iCut; itemno <= iClear; itemno++) {
DisableItem(mnu, itemno);
}
}
}

/* enable/disable the close menu as appropriate */
if (NAcloseitem) {
MenuHandle mnu = GetMHandle(mFile);

if (window != (WindowPtr) NULL && (winp == (na_win*) NULL
|| winp->pwin != window || winp->flags & NA_CLOSEBOX)) {
EnableItem(mnu, NAcloseitem);
} else {
DisableItem(mnu, NAcloseitem);
}
}

/* call menu proc to enable/disable items as appropriate */
if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
status = (*winp->menup)(winp, (WORD) 0, (WORD) key);
}
if (status == NA_NOTPROCESSED && NAmenup != (na_menup) NULL) {
status = (*NAmenup)(winp, (WORD) 0, (WORD) key);
}
if (status != NA_NOTPROCESSED) return (status);

/* get menu selection */
{
long menusel = (key == 0) ? MenuSelect(mselpoint) : MenuKey(key);

itemno = LOWORD(menusel);
if ((menuid = HIWORD(menusel)) == 0) menuid = 1;
}

/* check for DA menu items */
switch (menuid) {
case mApple: /* check for a desk accessary selection */
if (itemno > NAappleitems) {
PCstr mItem[256];

GetItem(GetMHandle(menuid), itemno, mItem);
OpenDeskAcc(mItem);
menuid = 1;
}
break;

case mFile: /* check for the close menu item for DAs */
if (itemno == NAcloseitem && NAisDAWindow(window)) {
CloseDeskAcc(((WindowPeek) window)->windowKind);
menuid = 1;
}
break;

case mEdit: /* check for the edit menu for DAs */
if (NAhasedit && itemno <= iClear && SystemEdit(itemno - iUndo)) {
menuid = 1;
}
break;
}

/* call menu proc to handle/disable items */
if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
status = (*winp->menup)(winp, menuid, itemno);
}
if (status != NA_PROCESSED && NAmenup != (na_menup) NULL) {
status = (*NAmenup)(winp, menuid, itemno);
}

/* if close item wasn't processed, process it */
if (status == NA_NOTPROCESSED && menuid == mFile && itemno == NAcloseitem) {
status = NA_REQCLOSE;
}

/* turn off the menu */
HiliteMenu(0);

return (status);
}

/* set the cursor icon appropriately
*/
#ifdef __STDC__
static void AdjustCursor(na_win *winp, Point gmouse, Boolean active)
#else
static void AdjustCursor(winp, gmouse, active)
na_win *winp;
Point gmouse;
Boolean active;
#endif
{
short status = NA_NOTPROCESSED;

/* don't change the cursor when in wrong window */
if (active && FrontWindow() != winp->pwin) return;

/* if the cursor is on */
if (winp->flags & NA_CURSORON) {
/* and the point moves outside the cursor region or window is deactivated
* turn cursor off */
if (!active || PtInRgn(gmouse, winp->uncrsrRgn)) {
winp->flags &= ~NA_CURSORON;
if (winp->cursorp == (na_cursorp*) NULL) {
SetCursor(&QD(arrow));
} else {
goto DOCURSORP;
}
}

/* if the cursor is off and the point moves into the window, turn cursor on */
} else if (PtInRgn(gmouse, winp->cursorRgn)) {
winp->flags |= NA_CURSORON;
if (winp->cursorp == (na_cursorp) NULL) {
SetCursor(&NAibeam);
} else {
DOCURSORP:
GlobalToLocal(&gmouse);
status = (*winp->cursorp)(winp, gmouse);
}
}

/* if cursor event was processed, reset the un-cursor region */
if (status == NA_PROCESSED) NAcalcCursor(winp);
}


/* export routines */

/* save the current window position in a resource file
*/
void NAsaveWin(winp)
na_win *winp;
{
Rect *rptr;
WindowPtr window = winp->pwin;
Handle wind = GetResource('WIND', winp->resid);

HLock(wind);
rptr = (Rect *) *wind;
rptr->right = (rptr->left = -window->portBits.bounds.left)
+ window->portRect.right;
rptr->bottom = (rptr->top = -window->portBits.bounds.top)
+ window->portRect.bottom;
ChangedResource(wind);
HUnlock(wind);
}

/* calculate the cursor regions for Multi-Finder
*/
void NAcalcCursor(winp)
na_win *winp;
{
if (winp->cursorRgn != (RgnHandle) NULL) {
if (winp->uncrsrRgn == (RgnHandle) NULL) winp->uncrsrRgn = NewRgn();
DiffRgn(NAfullRgn, winp->cursorRgn, winp->uncrsrRgn);
}
}

/* lock a window context
*/
na_win *NAlockWindow(winh)
na_win **winh;
{
if (winh == (na_win**) NULL) return ((na_win*) NULL);
if (!(*winh)->locks++) {
MoveHHi((Handle) winh);
HLock((Handle) winh);
}

return (*winh);
}

/* request or force a window to close
*/
#ifdef __STDC__
short NAcloseWindow(na_win *winp, short status)
#else
short NAcloseWindow(winp, status)
na_win *winp;
short status;
#endif
{
na_win **winh, ***whp;
short childstatus;
na_closep closeproc = (na_closep) NULL;

if (winp == (na_win*) NULL) return (NA_NOTPROCESSED);
switch (status) {
case NA_REQCLOSE:
/* check if window ready to close */
status = NA_CLOSED;
if ((closeproc = winp->closep) != (na_closep) NULL) {
status = (*closeproc)(winp);
closeproc = winp->closep == closeproc ? (na_closep) NULL : closeproc;
}
if (status > NA_CLOSED) break;
case NA_CLOSED:
/* close children */
childstatus = NAcloseWindows(winp->child, NA_REQCLOSEALL);
/* clear current window */
if (winp == NAwin) NAwin = (na_win*) NULL;
/* reset the cursor */
if (winp->flags & NA_CURSORON) SetCursor(&QD(arrow));
/* dispose of any cursor regions */
if (winp->cursorRgn != (RgnHandle) NULL) DisposeRgn(winp->cursorRgn);
if (winp->uncrsrRgn != (RgnHandle) NULL) DisposeRgn(winp->uncrsrRgn);
/* close the window */
if (winp->pwin != (WindowPtr) NULL) {
if (winp->flags & NA_DIALOGWINDOW) {
DisposDialog((DialogPtr) winp->pwin);
} else {
DisposeWindow(winp->pwin);
}
}
/* remove from window list */
winh = (na_win**) RecoverHandle((Ptr) winp);
#ifdef DEBUG
if (MemError() != noErr || *winh != winp) {
NAdebug("Handle error: pointer: %x, handle: %x, error: %d, zone: %x\015",
(long) winp, (long) winh, (long) MemError(),
(long) GetZone());
Debugger();
}
#endif /* DEBUG */
whp = &NAhead;
if (winp->parent != (na_win**) NULL) whp = &(*winp->parent)->child;
while (*whp != (na_win**) NULL) {
if (*whp == winh) {
*whp = winp->next;
} else {
whp = &(**whp)->next;
}
}
/* relink children in list */
if (childstatus > NA_ALLCLOSED) {
*whp = winp->child;
do {
(**whp)->parent = winp->parent;
whp = &(**whp)->next;
} while (*whp != (na_win**) NULL);
*whp = winp->next;
}
/* remove from task list */
whp = &NAtask;
while (*whp != (na_win**) NULL && *whp != winh) {
whp = &(**whp)->task;
}
*whp = winp->task;
NActask = (na_win**) NULL;
/* after-close function */
if (closeproc != (na_closep) NULL) (*closeproc)(winp);
/* destroy window structure */
DisposHandle((Handle) winh);
if (status < NA_CLOSED) {
if ((status = NAcloseWindows(NAhead, status)) > NA_CLOSED) {
status = NA_CLOSED;
}
}
break;
}

return (status);
}

#ifdef __STDC__
short NAcloseWindows(na_win **winh, short status)
#else
short NAcloseWindows(winh, status)
na_win **winh;
short status;
#endif
{
na_win *winp, **lasth;
short substatus;

while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
lasth = winh;
winh = winp->next;
substatus = NAcloseWindow(winp, status + 2);
if (substatus > NA_CLOSED) {
NAunlockWindowh(lasth, winp);
return (NA_NOTPROCESSED);
}
if (substatus < NA_CLOSED) return (substatus);
}

return (NA_ALLCLOSED);
}

/* remove the window on a mouse-up event
*/
#ifdef __STDC__
static short aboutmouse(na_win *winp, Point mousep, short type, short mods)
#else
static short aboutmouse(winp, mousep, type, mods)
na_win *winp;
Point mousep;
short type, mods;
#endif
#ifdef applec
#pragma unused (winp, mousep, mods)
#endif
{
return (type & 1 ? NA_REQCLOSE : NA_PROCESSED);
}

/* a standard about box init procedure
*/
short NAabout(winp, dptr)
na_win *winp;
long *dptr;
#ifdef applec
#pragma unused (dptr)
#endif
{
short item;

ShowWindow(winp->pwin);
winp->mousep = aboutmouse;

return (NA_PROCESSED);
}

/* flash a button in a dialog box for equivalent keypresses
*/
#ifdef __STDC__
void NAflashButton(DialogPtr dialog, short item)
#else
void NAflashButton(dialog, item)
DialogPtr dialog;
short item;
#endif
{
long scratch;
short type;
Handle ctrl;
Rect box;

GetDItem(dialog, item, &type, &ctrl, &box);
if (type == ctrlItem + btnCtrl) {
HiliteControl((ControlHandle) ctrl, 1);
Delay(5, &scratch);
HiliteControl((ControlHandle) ctrl, 0);
}
}

/* draw the default button
*/
void NAdefaultButton(dialog)
DialogPtr dialog;
{
Rect tmpRect;

NAgetDRect(dialog, iOk, &tmpRect);
{
PenState pnState;

GetPenState(&pnState);
PenNormal();
PenSize(3, 3);
InsetRect(&tmpRect, -4, -4);
FrameRoundRect(&tmpRect, 16, 16);
SetPenState(&pnState);
}
}

/* send an event message to all windows
*/
short NAallWindows(winh, pevent)
na_win **winh;
EventRecord *pevent;
{
na_win *winp, **oldwinh;
short status = NA_NOTPROCESSED;

while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
oldwinh = winh;
winh = winp->next;
if (winp->miscp != (na_miscp) NULL) {
GrafPtr tempPort;

GetPort(&tempPort);
SetPort(winp->pwin);
status = (*winp->miscp)(winp, pevent);
SetPort(tempPort);
}
if ((status == NA_CLOSED || status == NA_REQCLOSE)
&& NAcloseWindow(winp, status) == NA_CLOSED) {
continue;
}
NAunlockWindowh(oldwinh, winp);
if (status == NA_ALLCLOSED || status == NA_REQCLOSEALL) {
if (NAcloseWindows(NAhead, status) == NA_ALLCLOSED) {
return (NA_ALLCLOSED);
}
/* make sure our handle is still valid */
if (GetHandleSize((Handle) oldwinh) == 0) continue;
}
if ((*oldwinh)->child != (na_win**) NULL &&
NAallWindows((*oldwinh)->child, pevent) == NA_ALLCLOSED) {
return (NA_ALLCLOSED);
}
}

return (NA_PROCESSED);
}

/* apple event handler
*/
pascal OSErr NArequiredAE(AppleEvent *, AppleEvent *, long);
pascal OSErr NArequiredAE(event, reply, ref)
AppleEvent *event, *reply;
long ref;
{
na_openp openp = (na_openp) ref;
OSErr err;
DescType actualType, eventID;
Size actualSize;
AEDescList doclist;
long count, i;
short gotdoc;
FSSpec fspec;
AEKeyword keywd;

err = AEGetAttributePtr(event, keyEventIDAttr, typeType, &actualType,
(Ptr) &eventID, sizeof (eventID), &actualSize);
if (err == noErr) {
gotdoc = 0;
if (eventID == kAEOpenDocuments || eventID == kAEPrintDocuments) {
err = AEGetParamDesc(event, keyDirectObject, typeAEList, &doclist);
if (err == noErr) gotdoc = 1;
}
if (err == noErr) {
err = AEGetAttributePtr(event, keyMissedKeywordAttr, typeWildCard,
&actualType, NULL, 0, &actualSize);
if (err == errAEDescNotFound) {
err = noErr;
} else if (err == noErr) {
err = errAEEventNotHandled;
}
}
if (err == noErr) switch (eventID) {
case kAEOpenApplication:
if (NAmenup && NAnewitem) {
aestatus = (*NAmenup)(NULL, mFile, NAnewitem);
}
break;
case kAEOpenDocuments:
case kAEPrintDocuments:
err = AECountItems(&doclist, &count);
if (err != noErr) break;
for (i = 1; i <= count; ++i) {
err = AEGetNthPtr(&doclist, i, typeFSS, &keywd, &actualType,
(Ptr) &fspec, sizeof (fspec), &actualSize);
if (err != noErr) break;
if (!openp || (*openp)(eventID == kAEOpenDocuments
? appOpen : appPrint, 0, &fspec) < 0) {
err = errAEEventNotHandled;
break;
}
}
break;
case kAEQuitApplication:
aestatus = NA_ALLCLOSED;
if (NAhead != NULL) {
aestatus = NAcloseWindows(NAhead, NA_REQCLOSEALL);
if (aestatus != NA_ALLCLOSED) err = userCanceledErr;
}
break;
}
if (gotdoc) {
AEDisposeDesc(&doclist);
}
}

return (err);
}

/* call the main loop procedure
*/
void NAmainloop()
{
na_win *winp;
Boolean gotEvent;
Boolean dialogAction;
EventRecord event;
Point mouse;
short status;
short itemHit;
DialogPtr dialog;

UnloadSeg((Ptr) NAinit); /* unload the initialize routine */

MAINLOOP:
/* check for a window in front */
{
WindowPtr window;

if ((winp = NAwin) == (na_win*) NULL
&& (window = FrontWindow()) != (WindowPtr) NULL
&& (NAwin = winp = NAlockWindow(GetWinH(window))) != (na_win *) NULL) {
SetPort(window);
}
}

/* get an event */
{
RgnHandle rgn = NAfullRgn;
short delay = NAdelay;

/* if there is an app window in front, use app delay & cursor region */
if (winp != (na_win*) NULL) {
delay = winp->delay;
if (winp->cursorRgn != (RgnHandle) NULL && !NAinBack) {
rgn = winp->cursorRgn;
if (!(winp->flags & NA_CURSORON)) rgn = winp->uncrsrRgn;
}
if (winp->mousepix && !(NAlastmouse & 1)) {
rgn = NAnullRgn;
delay = 0;
}
}
gotEvent = WaitNextEvent(everyEvent, &event, delay, rgn);
}
status = NA_NOTPROCESSED;

/* get mouse position */
mouse = event.where;
GlobalToLocal(&mouse);

/* check for dialog events */
dialogAction = FrontWindow() != (WindowPtr) NULL ? IsDialogEvent(&event) : false;
if (dialogAction && event.what != keyDown && event.what != autoKey
&& event.what != updateEvt) {
ControlHandle ctrl;

if (DialogSelect(&event, &dialog, &itemHit) && winp != (na_win*) NULL) {
DOCONTROLP:
if (winp->ctrlp != (na_ctrlp) NULL) {
NAgetDHandle(dialog, itemHit, &ctrl);
status = (*winp->ctrlp)(winp, mouse, itemHit, event.modifiers, ctrl);
gotEvent = false;
}
}
}

/* handle the event */
if (gotEvent) switch (event.what) {
case mouseUp:
/* deal with mouse up events to keep track of double/triple clicks */
if (NAlastmouse & 1) break;
++NAlastmouse;
NAmousetime = TickCount();
if (winp == (na_win*) NULL) break;
DOMOUSEP:
if (winp->mousep != (na_mousep) NULL) {
status = (*winp->mousep)(winp, mouse, NAlastmouse, event.modifiers);
}
break;

case mouseDown:
if (winp != (na_win*) NULL && winp->flags & NA_MODAL
&& !PtInRect(mouse, &winp->pwin->portRect)) {
SysBeep(10);
break;
}
{
short part;
WindowPtr window;

/* deal with mouse down events */
switch (part = FindWindow(event.where, &window)) {
case inMenuBar:
/* call an appropriate menu bar handler */
mselpoint = event.where;
status = DoMenu(winp, 0);
break;

case inSysWindow:
/* System Click in DA */
SystemClick(&event, window);
break;

case inContent:
/* click a window to front if not in front */
if (window != FrontWindow()) {
SelectWindow(window);
if (winp != (na_win*) NULL) NAunlockWindow(winp);
NAwin = (na_win*) NULL;
NAlastmouse = NA_RELEASE;
break;
}

/* don't bother processing further if no mouse proc */
if (winp == (na_win*) NULL) break;

/* check for control events */
if (winp->ctrlp != (na_ctrlp) NULL && winp->flags & NA_HASCONTROLS) {
ControlHandle hctl;
short item;

if ((item = FindControl(mouse, window, &hctl)) != 0
&& (status = (*winp->ctrlp)(winp, mouse, item,
event.modifiers, hctl)) != NA_NOTPROCESSED) {
break;
}
}

/* deal with double clicks */
if ((NAlastmouse & 1) && NAlastmouse < NA_RELEASE
&& event.when - NAmousetime <= GetDblTime()) {
if (++NAlastmouse > NA_DOWNN) NAlastmouse = NA_DOWNN;
} else {
NAlastmouse = NA_DOWN1;
}
NAmousept = mouse;

/* call the mouse handler */
goto DOMOUSEP;

case inDrag:
/* drag the window */
{
Rect tmpRect, bRect;
na_win **wh, *wp;

{
int four = 4;

tmpRect = QD(screenBits.bounds);
InsetRect(&tmpRect, four, four);
}
bRect = window->portBits.bounds;
DragWindow(window, event.where, &tmpRect);
if ((bRect.left != window->portBits.bounds.left
|| bRect.top != window->portBits.bounds.top) &&
(wp = NAlockWindow(wh = GetWinH(window))) != NULL) {
if (wp->flags & NA_SMARTSIZE) NAsaveWin(wp);
if (wp->cursorRgn != (RgnHandle) NULL) {
OffsetRgn(wp->cursorRgn,
bRect.left - window->portBits.bounds.left,
bRect.top - window->portBits.bounds.top);
NAcalcCursor(wp);
}
NAunlockWindowh(wh, wp);
}
}
break;

case inGoAway:
/* deal with the close window box */
if (TrackGoAway(window, event.where)) status = NA_REQCLOSE;
break;

case inGrow:
/* grow the window */
{
Rect tmpRect;
long growInfo;

/* assume there is a valid app window in front */
/* calculate min & max grow dimensions */
tmpRect = QD(screenBits.bounds);
tmpRect.bottom -= tmpRect.top;
tmpRect.right -= tmpRect.left;
tmpRect.top = winp->minh;
tmpRect.left = winp->minw;
if (winp->maxh) tmpRect.bottom = winp->maxh;
if (winp->maxw) tmpRect.right = winp->maxw;

/* check for resize proc */
if (winp->resizep != (na_resizep) NULL) {
status = (*winp->resizep)(winp, event.where, &tmpRect);
if (status == NA_PROCESSED) break;
goto RESIZEWINDOW;
}

/* grow, resize, and update the window */
if ((growInfo = GrowWindow(window, event.where, &tmpRect))) {
SizeWindow(window, LOWORD(growInfo), HIWORD(growInfo),
false);
goto RESIZEWINDOW;
}
}
break;

case inZoomIn:
case inZoomOut:
/* assume there is a valid app window in front */
/* track, zoom, and update the window */
if (TrackBox(window, event.where, part)) {
SetPort(window);
EraseRect(&window->portRect);
ZoomWindow(window, part, true);
RESIZEWINDOW:
if (winp != (na_win*) NULL) {
if (winp->flags & NA_SMARTSIZE) NAsaveWin(winp);
if (winp->updatep == (na_updatep) NULL ||
(status = (*winp->updatep)(winp, (Boolean) true))
== NA_NOTPROCESSED) {
DoDraw(winp, DO_RESIZE);
}
}
ValidRect(&window->portRect);
}
break;
}
}
break;

case keyDown:
case autoKey:
/* deal with keyboard events */
{
long key = event.message & charCodeMask;

/* translate command-foo to an appropriate menu operation */
if (!(winp->flags & NA_MODAL)) {
if ((event.modifiers & cmdKey) && event.what == keyDown &&
(status = DoMenu(winp, key)) != NA_NOTPROCESSED) {
break;
}
}

/* require an app window for further processing */
if (winp == (na_win*) NULL) break;

/* call the window's key handling procedure */
if (winp->keyp != (na_keyp) NULL) {
status = (*winp->keyp)(winp, winp->flags & NA_RAWKEY ? event.message : key,
event.modifiers);
}

/* if it's an unprocessed event in a dialog window */
if ((status == NA_NOTPROCESSED || status == NA_DPROCESSED)
&& (winp->flags & NA_DIALOGWINDOW)) {
ControlHandle ctrl;

/* check for return/ESC/command-. */
itemHit = 0;
if (status == NA_NOTPROCESSED) switch (key) {
case '\r':
case '\n':
NAgetDHandle((DialogPtr)winp->pwin, iOk, &ctrl);
if (ctrl && !(*ctrl)->contrlHilite) {
itemHit = iOk;
}
break;

case '.':
if (!(event.modifiers & cmdKey)) break;
case '\033':
itemHit = iCancel;
break;
}

/* if it's a special key, flash it's item */
dialog = winp->pwin;
if (itemHit) {
NAflashButton(dialog, itemHit);
} else if ((event.modifiers & cmdKey)
|| !DialogSelect(&event, &dialog, &itemHit)) {
break;
}

/* if there's a control procedure, call it, otherwise ignore */
if (winp->ctrlp != (na_ctrlp) NULL) goto DOCONTROLP;
}
}
break;

case activateEvt:
/* deal with activate windows based on activeFlag */
status = DoActivate((WindowPtr) event.message, winp,
event.modifiers & activeFlag, mouse);
break;

case updateEvt:
/* deal with update events with proper port setting, etc. */
{
na_win *wp;
WindowPtr window;
na_win **winh;
GrafPtr tempPort;

window = (WindowPtr) event.message;
BeginUpdate(window);
if ((wp = NAlockWindow(winh = GetWinH(window))) != (na_win*) NULL) {
GetPort(&tempPort);
SetPort(window);
if (wp->flags & NA_DIALOGUPDATE) {
UpdtDialog(window, window->visRgn);
status = NA_PROCESSED;
}
if (wp->updatep == (na_updatep) NULL
|| (status = (*wp->updatep)(wp, (Boolean) false))
== NA_NOTPROCESSED) {
DoDraw(wp, DO_UPDATE);
}
if (status == NA_NOTPROCESSED && dialogAction) {
(void) DialogSelect(&event, &dialog, &itemHit);
}
SetPort(tempPort);
NAunlockWindowh(winh, wp);
}
EndUpdate(window);
}
break;

case diskEvt:
/* let the user format bad disks */
if (HIWORD(event.message) != noErr) {
Point ptemp;

SetPt(&ptemp, 0x0070, 0x0050);
(void) DIBadMount(ptemp, event.message);
} else {
status = NAallWindows(NAhead, &event);
}
break;

case networkEvt:
case driverEvt:
case app1Evt:
case app2Evt:
case app3Evt:
/* send event to all windows */
status = NAallWindows(NAhead, &event);
break;

case osEvt:
switch ((event.message >> 24) & 0xff) {
case suspendResumeMessage:
status = DoActivate(FrontWindow(), winp,
!(NAinBack = !(event.message & resumeFlag)), mouse);
break;

case mouseMovedMessage:
/* only interesting if a window is in front */
if (NAinBack || winp == (na_win*) NULL) break;

{
short mousepix = winp->mousepix;

/* deal with mouse dragging */
if (mousepix && !(NAlastmouse & 1)) {
if (NAlastmouse != NA_DRAG) {
Rect tmpRect;

InsetRect(&tmpRect, -mousepix, -mousepix);
if (PtInRect(mouse, &tmpRect)) break;
NAlastmouse = NA_DRAG;
}
goto DOMOUSEP;

/* deal with cursor moving in/out of window */
} else if (winp->cursorRgn != (RgnHandle) NULL) {
AdjustCursor(winp, event.where, true);
}
}
break;
}
break;

case kHighLevelEvent:
if (NAgestaltBits & NA_HASAEVENTS) {
aestatus = status;
(void) AEProcessAppleEvent(&event);
status = aestatus;
}
break;
}

/* call the idle procedure of the front window */
if ((winp = NAwin) != (na_win*) NULL && !NAinBack
&& status >= NA_NOTPROCESSED && winp->idlep != (na_idlep) NULL) {
status = (*winp->idlep)(winp);
}

/* deal with window/app close requests and events */
switch (status) {
case NA_ALLCLOSED:
case NA_REQCLOSEALL:
status = NAcloseWindows(NAhead, status);
break;

case NA_CLOSED:
case NA_REQCLOSE:
status = NAcloseWindow(winp, status);
break;

default:
/* call the next task procedure */
if (NAtask != (na_win**) NULL) {
static BYTE prioritycnt;
na_win *wp;
GrafPtr tempPort;

if (NActask == (na_win**) NULL) {
NActask = NAtask;
prioritycnt = (*NAtask)->priority;
}
if ((wp = NAlockWindow(NActask)) != (na_win*) NULL
&& wp->taskp != (na_taskp) NULL) {
GetPort(&tempPort);
if (wp->pwin != (WindowPtr) NULL) SetPort(wp->pwin);
switch (status = (*wp->taskp)(wp)) {
case NA_REQCLOSE:
case NA_CLOSED:
NAcloseWindow(wp, status);
break;
}
SetPort(tempPort);
}
if (!prioritycnt-- && (NActask = wp->task) != (na_win**) NULL) {
prioritycnt = (*NActask)->priority;
}
NAunlockWindowh(NActask, wp);
}
break;
}
if (status != NA_ALLCLOSED) goto MAINLOOP;

while (NAtask != NULL) NAcloseWindow(NAlockWindow(NAtask), NA_REQCLOSE);

DisposeRgn(NAfullRgn);
DisposeRgn(NAnullRgn);
}

/* position a rectangle based on screen size
*/
#ifdef __STDC__
Rect *NAscreenrect(short position)
#else
Rect *NAscreenrect(position)
short position;
#endif
{
static short stacktimes = 0;
static Rect sb;
short topoffset, leftoffset;

/* calculate the position to open the window */
{
int four = 4;

sb = QD(screenBits.bounds);
InsetRect(&sb, four, four);
sb.top += MBarHeight;
}
if (position & NA_TITLEOFFSET) {
sb.top += 18;
}
{
short width, height;

width = sb.right - sb.left;
height = sb.bottom - sb.top;
if (position & 0x03) {
width = (width * (position & 0x03)) >> 2;
}
if (position & 0x0c) {
height = (height * ((position & 0x0c) >> 2)) >> 2;
}
if (position & NA_TOPSCN) {
sb.bottom = sb.top + height;
} else if (position & NA_BOTTOMSCN) {
sb.top = sb.bottom - height;
} else {
short bw = (sb.bottom - sb.top - height) >> 1;
sb.top += bw;
sb.bottom -= bw;
}
if (position & NA_LEFTSCN) {
sb.right = sb.left + width;
} else if (position & NA_RIGHTSCN) {
sb.left = sb.right - width;
} else {
short bw = (sb.right - sb.left - width) >> 1;

sb.left += bw;
sb.right -= bw;
}
if (position & NA_STACK) {
if (stacktimes >= 5) {
stacktimes = 0;
}
topoffset = 22 * stacktimes;
leftoffset = (4 - stacktimes) * 4;
if (sb.top + topoffset < sb.bottom) sb.top += topoffset;
if (sb.left + leftoffset < sb.right) sb.left += leftoffset;
++stacktimes;
}
}

return (&sb);
}

/* create a new window/dialog/task structure
*/
#ifdef __STDC__
short NAwindow(Rect *rpos, long flags, char *title, short res, long *initdata,
long datasize, na_initp initp)
#else
short NAwindow(rpos, flags, title, res, initdata, datasize, initp)
Rect *rpos;
long flags;
char *title;
short res;
long *initdata;
long datasize;
na_initp initp;
#endif
{
GrafPtr tmpPort;
short procID;
short status;
Boolean goAwayFlag, visible;
na_win **winh, *winp;
WindowPtr behind, prev;
PCstr wtitle[256];

/* save previous window */
prev = FrontWindow();

/* set up flags for the NewWindow call */
goAwayFlag = (flags & NA_CLOSEBOX);
visible = (flags & NA_NOTVISIBLE) ? false : true;
behind = (flags & NA_BEHIND && NAwin != (na_win*) NULL) ? NAwin->pwin : (WindowPtr) -1;

/* decide on the correct procID */
{
short proc = rDocProc;

if ((flags & NA_ROUNDBORDER) != NA_ROUNDBORDER) {
proc = plainDBox;
if (flags & NA_SHADOWBORDER) proc = altDBoxProc;
if (flags & NA_DOUBLEBORDER) proc = dBoxProc;
if (flags & NA_TITLEBAR) proc = documentProc;
if (!(flags & NA_GROWBOX)
&& proc == documentProc) proc |= noGrowDocProc;
if (flags & NA_ZOOMBOX) proc |= zoomDocProc;
}
procID = proc;
}

/* get the window title to a pacsal string */
if (title) CtoPCstrcpy(wtitle, title);

/* allocate memory and copy the user data */
if (!datasize) datasize = sizeof (na_win);
winh = (na_win**) NewHandleClear((Size) datasize);
if (winh == (na_win**) NULL) return (NA_NOTPROCESSED);
MoveHHi((Handle) winh);
HLock((Handle) winh);
winp = *winh;
if (initdata != NULL && flags & NA_COPYDATA) {
char *newdata;
char *dcopy = (char *) initdata;

datasize -= sizeof (na_win);
for (newdata = (char*) winp + sizeof (na_win); datasize > 0; datasize--) {
*newdata = *dcopy++;
newdata++;
}
}

/* initialize winp parameters */
winp->locks = 1;
winp->delay = NAdelay;
winp->flags = flags;
winp->minw = 128;
winp->minh = 64;
winp->resid = res;

/* install in window tree */
if (flags & NA_CHILDWINDOW && NAwin != (na_win*) NULL) {
winp->parent = (na_win**) RecoverHandle((Ptr)NAwin);
winp->next = NAwin->child;
NAwin->child = winh;
} else {
winp->next = NAhead;
NAhead = winh;
}

/* install in task list */
if (flags & NA_HASTASK) {
winp->task = NAtask;
NAtask = winh;
}

{
WindowPtr window;

/* open the window appropriately */
switch (flags & (NA_COLORWINDOW | NA_DIALOGWINDOW)) {
case NA_DIALOGWINDOW:
case (NA_DIALOGWINDOW | NA_COLORWINDOW):
if (flags & NA_USERESOURCE) {
window = (WindowPtr) GetNewDialog(res, (Ptr) NULL, behind);
} else {
Handle items;

items = GetResource('DITL', res);
DetachResource(items);
if (flags & NA_COLORWINDOW) {
window = (WindowPtr) NewCDialog((Ptr) NULL, rpos, wtitle,
visible, procID, behind, goAwayFlag, (long) winh, items);
} else {
window = (WindowPtr) NewDialog((Ptr) NULL, rpos, wtitle,
visible, procID, behind, goAwayFlag, (long) winh, items);
}
}
break;

case NA_COLORWINDOW:
if (flags & NA_USERESOURCE) {
window = (WindowPtr) GetNewCWindow(res, (Ptr) NULL, behind);
} else {
window = (WindowPtr) NewCWindow((Ptr) NULL, rpos, wtitle,
visible, procID, behind, goAwayFlag, (long) winh);
}
break;

default:
if (flags & NA_USERESOURCE) {
window = GetNewWindow(res, (Ptr) NULL, behind);
} else {
window = NewWindow((Ptr) NULL, rpos, wtitle, visible, procID,
behind, goAwayFlag, (long) winh);
}
break;
}
if (title && (flags & NA_USERESOURCE)) SetWTitle(window, wtitle);
winp->pwin = window;

/* activate the window */
GetPort(&tmpPort);
SetPort(window);

/* additional options for windows from resources */
if (flags & NA_USERESOURCE) {
SetWRefCon(window, (long) winh);

/* force the size */
if (flags & NA_FORCESIZE) {
MoveWindow(window, rpos->left, rpos->top, false);
SizeWindow(window, rpos->right - rpos->left, rpos->bottom - rpos->top, false);
}
}
{
Rect wsize, sb;

/* get the screen bounds */
{
short four = 4;

sb = QD(screenBits.bounds);
InsetRect(&sb, four, four);
}

/* recenter a window -- great for dialog boxes */
wsize = window->portRect;
LocalToGlobal((Point *)&wsize.top);
if (flags & NA_RECENTER) {
LocalToGlobal((Point *)&wsize.bottom);
wsize.top = sb.top + (((sb.bottom - sb.top) - (wsize.bottom - wsize.top)) >> 1);
wsize.left = sb.left + (((sb.right - sb.left) - (wsize.right - wsize.left)) >> 1);
MoveWindow(window, wsize.left, wsize.top, false);
}

/* make sure the window is on the screen */
if (wsize.top > sb.bottom || wsize.left > sb.right) {
short coord = 60;

MoveWindow(window, coord, coord, false);
}
}

/* call the init procedure */
if ((status = (*initp)(winp, initdata)) >= NA_NOTPROCESSED) {

/* draw the window immediately for better look & update has first newsize */
if (winp->updatep == (na_updatep) NULL
|| (status = (*winp->updatep)(winp, (Boolean) true))
== NA_NOTPROCESSED) {
DoDraw(winp, FrontWindow() != window ? DO_RESIZE | DO_DEACTIVATE :
DO_RESIZE);
}
if (flags & NA_DIALOGUPDATE) DrawDialog(window);
ValidRect(&window->portRect);
}

/* deal with close requests/events result codes */
switch (status) {
case NA_ALLCLOSED:
case NA_REQCLOSEALL:
status = NAcloseWindows(NAhead, status);
break;

case NA_CLOSED:
case NA_REQCLOSE:
status = NAcloseWindow(winp, status);
break;

default:
NAunlockWindowh(winh, winp);
break;
}

/* give a nice return value & clean up the port */
if (status == NA_NOTPROCESSED) status = NA_PROCESSED;
if (FrontWindow() != window || status != NA_PROCESSED) SetPort(tmpPort);
}

return (status);
}

/* add a new task to the task list, calling init procedure with data pointer
*/
void NAaddtask(taskp, size)
na_taskp taskp;
long size;
{
na_win **task, *winp;

if (!size) size = sizeof (na_win);
task = (na_win **) NewHandleClear(size);
(*task)->taskp = taskp;
(*task)->task = NAtask;
NAtask = task;
}
END_OF_FILE
fi
if test -f 'mpack-1.0/dosos.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/dosos.c'\"
else
echo shar: Extracting \"'mpack-1.0/dosos.c'\" \(5716 bytes\)
cat >'mpack-1.0/dosos.c' <<'END_OF_FILE'
/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "xmalloc.h"
#include "common.h"

extern int errno;

int overwrite_files = 0;

/* The name of the file we're writing */
static char *output_fname = 0;

/* Characters that can be in filenames */
#define GOODCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

/* Generate a message-id */
char *os_genid()
{
static time_t curtime;
static char *hostname;
char *result;

if (curtime == 0) {
time(&curtime);

hostname = getenv("HOSTNAME");
if (!hostname) hostname="random-pc";
}

result = malloc(25+strlen(hostname));
sprintf(result, "%lu@%s", curtime++, hostname);
return result;
}

/* Create and return directory for a message-id */
char *os_idtodir(id)
char *id;
{
static char buf[4096];
int len = 0;
char *p;

if (getenv("TMP")) {
strcpy(buf, getenv("TMP"));
}
else {
strcpy(buf, "\\tmp");
(void)mkdir(buf);
}
strcat(buf, "\\parts");
(void)mkdir(buf);

p = buf + strlen(buf);
*p++ = '\\';

while (*id && len < 11) {
if (strchr(GOODCHARS, *id)) {
if (len++ == 8) *p++ = '.';
*p++ = *id;
}
id++;
}
*p = '\0';
if (mkdir(buf) == -1 && errno != EACCES) {
perror(buf);
return 0;
}
*p++ = '\\';
*p = '\0';
return buf;
}

/*
* We are done with the directory returned by os_idtodir()
* Remove it
*/
os_donewithdir(dir)
char *dir;
{
char *p;

/* Remove trailing slash */
p = dir + strlen(dir) - 1;
*p = '\0';

rmdir(dir);
}

/*
* Create a new file, with suggested filename "fname".
* "fname" may have come from an insecure source, so clean it up first.
* It may also be null.
* "contentType" is passed in for use by systems that have typed filesystems.
* "binary" is nonzero if the new file should be opened in binary mode.
*/
FILE *os_newtypedfile(fname, contentType, binary)
char *fname;
char *contentType;
int binary;
{
char *p, *q;
int len, sawdot;
static int filesuffix=0;
char buf[128], *descfname=0;
FILE *outfile = 0;

if (!fname) fname = "";

/* Chop off any drive specifier, convert / to \ */
if (*fname && fname[1] == ':') fname +=2;
for (p = fname; *p; p++) if (*p == '/') *p = '\\';

/* If absolute path name, chop to tail */
if (*fname == '\\') {
p = strrchr(fname, '\\');
fname = p+1;
}

/* Clean out bad characters, create directories along path */
for (p=q=fname, len=sawdot=0; *p; p++) {
if (*p == '\\') {
if (!strncmp(p, "\\..\\", 4)) {
p[1] = p[2] = 'X';
}
*q = '\0';
(void) mkdir(fname);
*q++ = '\\';
len = sawdot = 0;
}
else if (*p == '.' && !sawdot) {
*q++ = '.';
sawdot++;
len = 0;
}
else if (len < (sawdot ? 3 : 8) && strchr(GOODCHARS, *p)) {
*q++ = *p;
len++;
}
}
*q = '\0';

if (!fname[0]) {
do {
if (outfile) fclose(outfile);
sprintf(buf, "part%d", ++filesuffix);
} while (outfile = fopen(buf, "r"));
fname = buf;
}
else if (!overwrite_files && (outfile = fopen(fname, "r"))) {
/* chop off suffix */
p = strrchr(fname, '\\');
if (!p) p = fname;
p = strchr(p, '.');
if (*p) *p = '\0';

/* append unique number */
do {
fclose(outfile);
sprintf(buf, "%s.%d", fname, ++filesuffix);

} while (outfile = fopen(buf, "r"));
fname = buf;
}

outfile = fopen(fname, binary ? "wb" : "w");
if (!outfile) {
perror(fname);
}

if (output_fname) free(output_fname);
output_fname = strsave(fname);

if (strlen(fname) > sizeof(buf)-6) {
descfname = xmalloc(strlen(fname)+6);
}
else {
descfname = buf;
}
strcpy(descfname, fname);

p = strrchr(descfname, '\\');
if (!p) p = descfname;
if (p = strrchr(p, '.')) *p = '\0';

strcat(descfname, ".dsc");
(void) rename(TEMPFILENAME, descfname);
if (descfname != buf) free(descfname);

fprintf(stdout, "%s (%s)\n", output_fname, contentType);

return outfile;
}

/*
* Warn user that the MD5 digest of the last file created by os_newtypedfile()
* did not match that supplied in the Content-MD5: header.
*/
os_warnMD5mismatch()
{
char *warning;

warning = xmalloc(strlen(output_fname) + 100);
sprintf(warning, "%s was corrupted in transit",
output_fname);
warn(warning);
free(warning);
}

/*
* Report an error (in errno) concerning a filename
*/
os_perror(file)
char *file;
{
perror(file);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/unixunpk.man' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/unixunpk.man'\"
else
echo shar: Extracting \"'mpack-1.0/unixunpk.man'\" \(1526 bytes\)
cat >'mpack-1.0/unixunpk.man' <<'END_OF_FILE'
.TH MUNPACK 1
.SH NAME
munpack \- unpack messages in MIME or split-uuencode format
.SH SYNOPSIS
.B munpack
[
.B \-f
]
[
.B \-C
.I directory
]
[
.I "filename \&..."
]
.SH DESCRIPTION
The
.I munpack
program reads each RFC-822 message
.I filename
and writes all non-text MIME parts or split-uuencoded files as files.
If no filename argument is given,
.B munpack
reads from standard input.
.LP
If the message suggests a file name to use for the imbedded part, that
name is cleaned of potential problem characters and used for the
output file. If the suggested filename includes subdirectories, they
will be created as necessary.
If the message does not suggest a file name, the names
"part01", "part02", etc are used in sequence.
.LP
If the imbedded part was preceded with textual information, that
information is also written to a file. The file is named the same as
the imbedded part, with any filename extension replaced with ".desc".
.SH OPTIONS
.TP
.B \-f
Force overwriting of existing files. If a message suggests a file
name of an existing file, the file will be overwritten. Without this
flag,
.B
munpack
appends ".1", ".2", etc to find a nonexistent file.
.TP
.BI \-C " directory"
Change the current directory to
.I directory
before reading any files. This is useful when invoking
.B munpack
from a mail or news reader.
.SH ENVIRONMENT
.TP
.B TMPDIR
Directory to store temporary files. Default is /tmp.
.SH FILES
.TP
.B $TMPDIR/message-parts-$USER/
Directory used to store partial messages awaiting reassembly.
END_OF_FILE
fi
echo 'End of part 1 (of 6).'
echo 01 >> _shar_private
sort -n -u _shar_private | {
MISSING=""
read j
for i in 01 02 03 04 05 06 ; do
if test $i = "$j" ; then
read j
else
MISSING="$MISSING $i"
fi
done
if test -z "${MISSING}" ; then
echo Finished extracting all parts!
rm -f _shar_private
else
echo You still need to extract the following parts:
echo " ${MISSING}"
fi
}
# End of shell archive.
exit 0

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:29:43 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 59
Archive-name: mpack-1.0/02

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:

# "End of part 2 (of 6)."


# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'

if test -f 'mpack-1.0/decode.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/decode.c'\"
else
echo shar: Extracting \"'mpack-1.0/decode.c'\" \(23269 bytes\)
cat >'mpack-1.0/decode.c' <<'END_OF_FILE'
/*
* Decode MIME parts.
*/


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "xmalloc.h"
#include "common.h"

extern char *os_idtodir();
extern FILE *os_newtypedfile();
extern char *md5digest();

/* List of pending multipart boundaries */
struct boundary {
char **id;
int count;
int alloc;
};

/* The possible content transfer encodings */
enum encoding { enc_none, enc_binary, enc_qp, enc_base64 };

typedef char **params;

char *ParseHeaders();
enum encoding parseEncoding();
params ParseContent();
char *getParam();

/*
* Read and handle an RFC 822 message from the file 'infile'.
*/
handleMessage(infile, defaultContentType, boundaries)
FILE *infile;
char *defaultContentType;
struct boundary *boundaries;
{
char *headers, *subject, *contentType, *contentDisposition, *contentMD5;
enum encoding contentEncoding;
params contentParams;
struct boundary newboundaries;

/* No passed-in boundary structure, create a new one */
if (!boundaries) {
boundaries = &newboundaries;
boundaries->id = 0;
boundaries->alloc = boundaries->count = 0;
}

/* Parse the headers, getting the ones we're interested in */
headers = ParseHeaders(infile, &subject, &contentType, &contentEncoding,
&contentDisposition, &contentMD5);

/* If no content type, or a non-MIME content type, use the default */
if (!contentType || !strchr(contentType, '/')) {
contentType = defaultContentType;
}
contentParams = ParseContent(&contentType);

if (!cistrcmp(contentType, "message/rfc822")) {
if (contentEncoding != enc_none && contentEncoding != enc_binary) {
warn("ignoring invalid content encoding on message/rfc822");
}

/* Simple recursion */
return handleMessage(infile, "text/plain", boundaries);
}
else if (!cistrcmp(contentType, "message/partial")) {
if (contentEncoding != enc_none && contentEncoding != enc_binary) {
warn("ignoring invalid content encoding on message/partial");
}
return handlePartial(infile, headers, contentParams, boundaries);
}
else if (!cistrncmp(contentType, "message/", 8)) {
/* Probably message/external. We don't care--toss it */
return ignoreMessage(infile, boundaries);
}
else if (!cistrncmp(contentType, "multipart/", 10)) {
if (contentEncoding != enc_none && contentEncoding != enc_binary) {
warn("ignoring invalid content encoding on multipart");
}
return handleMultipart(infile, contentType, contentParams,
boundaries);
}
else if (!cistrncmp(contentType, "text/", 5)) {
if (boundaries->count) {
return handleText(infile, contentEncoding, boundaries);
}
else if (subject) {
/* top-level text message, handle as possible uuencoded file */
return handleUuencode(infile, subject);
}
else {
return ignoreMessage(infile, boundaries);
}
}
else {
/* Some sort of attachment, extract it */
return saveToFile(infile, contentType, contentParams, contentEncoding,
contentDisposition, contentMD5, boundaries);
}
}

/*
* Skip whitespace and RFC-822 comments.
*/
SkipWhitespace(s)
char **s;
{
char *p = *s;
int commentlevel = 0;

while (*p && (isspace(*p) || *p == '(')) {
if (*p == '\n') {
p++;
if (*p != ' ' && *p != '\t') {
*s = 0;
return;
}
}
else if (*p == '(') {
p++;
commentlevel++;
while (commentlevel) {
switch (*p) {
case '\n':
p++;
if (*p == ' ' || *p == '\t') break;
/* FALL THROUGH */
case '\0':
*s = 0;
return;

case '\\':
p++;
break;

case '(':
commentlevel++;
break;

case ')':
commentlevel--;
break;
}
p++;
}
}
else p++;
}
if (*p == 0) {
*s = 0;
}
else {
*s = p;
}
}

/*
* Read and parse the headers of an RFC 822 message, returning them in
* a pointer to a static buffer. The headers are read from 'infile'.
* A pointer to the value of any Subject:, Content-Type:,
* Content-Disposition:, or Content-MD5: header is stored in the space
* pointed to by 'subjectp', 'contentTypep', contentDispositionp, and
* contentMD5p, respectively. The Content-Transfer-Encoding is stored
* in the enum pointed to by 'contentEncodingp'.
*/
#define HEADGROWSIZE 1000
char *ParseHeaders(infile, subjectp, contentTypep, contentEncodingp,
contentDispositionp, contentMD5p)
FILE *infile;
char **subjectp, **contentTypep;
enum encoding *contentEncodingp;
char **contentDispositionp, **contentMD5p;
{
static int alloced = 0;
static char *headers;
int left, len;
char *next, *val;

/* Read headers into buffer pointed to by "headers" */
if (!alloced) {
headers = xmalloc(alloced = HEADGROWSIZE);
}
next = headers;
*next++ = '\n'; /* Leading newline to make matching header names easier */
left = alloced - 2; /* Allow room for terminating null */

while (fgets(next, left, infile) && (*next != '\n' || next[-1] != '\n')) {
len = strlen(next);
left -= len;
next += len;

if (left < 100) {
len = next - headers;
alloced += HEADGROWSIZE;
left += HEADGROWSIZE;
headers = xrealloc(headers, alloced);
next = headers + len;
}
}

*next = '\0';

/* Look for the headers we find particularly interesting */
*subjectp = *contentTypep = *contentDispositionp = *contentMD5p = 0;
*contentEncodingp = enc_none;
for (next = headers; *next; next++) {
if (*next == '\n') {
switch(next[1]) {
case 's':
case 'S':
if (!cistrncmp(next+2, "ubject:", 7)) {
val = next+9;
SkipWhitespace(&val);
if (val) *subjectp = val;
}
break;

case 'c':
case 'C':
if (!cistrncmp(next+2, "ontent-type:", 12)) {
val = next+14;
SkipWhitespace(&val);
if (val) *contentTypep = val;
}
else if (!cistrncmp(next+2, "ontent-transfer-encoding:", 25)) {
*contentEncodingp = parseEncoding(next+27);
}
else if (!cistrncmp(next+2, "ontent-disposition:", 19)) {
val = next+21;
SkipWhitespace(&val);
if (val) *contentDispositionp = val;
}
else if (!cistrncmp(next+2, "ontent-md5:", 11)) {
val = next+13;
SkipWhitespace(&val);
if (val) *contentMD5p = val;
}
}
}
}
return headers;
}

/*
* Parse the Content-Transfer-Encoding: value pointed to by 's'.
* Returns the appropriate encoding enum.
*/
enum encoding parseEncoding(s)
char *s;
{
SkipWhitespace(&s);
if (s) {
switch (*s) {
case 'q':
case 'Q':
if (!cistrncmp(s+1, "uoted-printable", 15) &&
(isspace(s[16]) || s[16] == '(')) {
return enc_qp;
}
break;

case '7':
case '8':
if (!cistrncmp(s+1, "bit", 3) &&
(isspace(s[4]) || s[4] == '(')) {
return enc_none;
}
break;

case 'b':
case 'B':
if (!cistrncmp(s+1, "ase64", 5) &&
(isspace(s[6]) || s[6] == '(')) {
return enc_base64;
}
if (!cistrncmp(s+1, "inary", 5) &&
(isspace(s[6]) || s[6] == '(')) {
return enc_binary;
}
}
warn("ignoring unknown content transfer encoding\n");
}
return enc_none;
}

/*
* Parse the value of a Content-Type: header.
* 'headerp' points to a pointer to the input string.
* The pointer pointed to by 'headerp' is changed to point to
* a static buffer containing the content type stripped of whitespace
* and parameters. The parameters are converted to a type suitable for
* getParm() and returned.
*/
#define PARAMGROWSIZE 10
params ParseContent(headerp)
char **headerp;
{
char *header;
static int palloced = 0;
static char **param;
static int calloced = 0;
static char *cbuf;
char *p;
int nparam;

p = header = *headerp;

/* Find end of header, including continuation lines */
do {
p = strchr(p+1, '\n');
} while (p && isspace(p[1]));
if (!p) {
p = header + strlen(header);
}

/* If necessary, allocate/grow cbuf to hold header. */
if (p - header >= calloced) {
calloced = p - header + 1;
if (calloced < 200) calloced = 200;
cbuf = xrealloc(cbuf, calloced);
}

/* Copy header to cbuf */
strncpy(cbuf, header, p - header);
cbuf[p - header] = 0;
header = *headerp = cbuf;

nparam = 0;

/* Strip whitespace from content type */
/* ParseHeader() stripped leading whitespace */
p = header;
while (header && *header && *header != ';') {
while (*header && !isspace(*header) && *header != '(' &&
*header != ';') {
*p++ = *header++;
}
SkipWhitespace(&header);
}
if (!header || !*header) return 0;
header++;
*p = '\0';

/* Parse the parameters */
while (*header) {
SkipWhitespace(&header);
if (!header) break;

if (nparam+1 >= palloced) {
palloced += PARAMGROWSIZE;
param = (char **) xrealloc((char *)param, palloced * sizeof(char *));
}
param[nparam++] = header;

/* Find any separating semicolon. Pay attention to quoted-strings */
while (*header && *header != ';') {
if (*header == '\"') {
++header;
while (*header && *header != '\"') {
if (*header == '\\') {
++header;
if (!*header) break;
}
++header;
}
if (!*header) break;
}
else if (*header == '(') {
/* Convert comments to spaces */
p = header;
SkipWhitespace(&p);
if (!p) {
break;
}
while (header < p) *header++ = ' ';
header--;
}
header++;
}
if (*header) *header++ = '\0';
}
param[nparam] = 0;
return param;
}

/*
* Get the value of the parameter named 'key' from the content-type
* parameters 'cParams'. Returns a pointer to a static bufer which
* contains the value, or null if no such parameter was found.
*/
#define VALUEGROWSIZE 100
char *getParam(cParams, key)
params cParams;
char *key;
{
static char *value;
static int alloced = 0;
int left;
int keylen = strlen(key);
char *from, *to;

if (!cParams) return 0;

if (!alloced) {
value = xmalloc(alloced = VALUEGROWSIZE);
}

/* Find the named parameter */
while (*cParams) {
if (!cistrncmp(key, *cParams, keylen) &&
((*cParams)[keylen] == '=' || isspace((*cParams)[keylen]))) break;
cParams++;
}
if (!*cParams) return 0;

/* Skip over the "=" and any surrounding whitespace */
from = *cParams + keylen;
while (*from && isspace(*from)) from++;
if (*from++ != '=') return 0;
while (*from && isspace(*from)) from++;
if (!*from) return 0;

/* Copy value into buffer */
to = value;
left = alloced - 1;
if (*from == '\"') {
/* Quoted-string */
from++;
while (*from && *from != '\"') {
if (!--left) {
alloced += VALUEGROWSIZE;
value = xrealloc(value, alloced);
to = value + alloced - left - 2;
}
if (*from == '\\') {
from++;
if (!*from) return 0;
}
*to++ = *from++;
}
if (!*from) return 0;
}
else {
/* Just a token */
while (*from && !isspace(*from)) {
if (!--left) {
alloced += VALUEGROWSIZE;
value = xrealloc(value, alloced);
to = value + alloced - left - 2;
}
*to++ = *from++;
}
}
*to = '\0';
return value;
}

/*
* Get the value of the "filename" parameter in a Content-Disposition:
* header. Returns a pointer to a static buffer containing the value, or
* a null pointer if there was no such parameter.
*/
char *
getDispositionFilename(disposition)
char *disposition;
{
static char *value;
static int alloced = 0;
int left;
char *to;

if (!disposition) return 0;

/* Skip until we find ";" "filename" "=" tokens. */
for (;;) {
/* Skip until we find ";" */
while (*disposition != ';') {
if (!*disposition) return 0;
else if (*disposition == '\"') {
++disposition;
while (*disposition && *disposition != '\"') {
if (*disposition == '\\') {
++disposition;
if (!*disposition) return 0;
}
++disposition;
}
if (!*disposition) return 0;
}
else if (*disposition == '(') {
SkipWhitespace(&disposition);
if (!disposition) return 0;
disposition--;
}
disposition++;
}

/* Skip over ";" and trailing whitespace */
disposition++;
SkipWhitespace(&disposition);
if (!disposition) return 0;

/*
* If we're not looking at a "filename" token, go back
* and look for another ";". Otherwise skip it and
* trailing whitespace.
*/
if (cistrncmp(disposition, "filename", 8) != 0) continue;
disposition += 8;
if (!isspace(*disposition) && *disposition != '=' &&
*disposition != '(') {
continue;
}
SkipWhitespace(&disposition);
if (!disposition) return 0;

/* If we're looking at a ";", we found what we're looking for */
if (*disposition++ == '=') break;
}

SkipWhitespace(&disposition);
if (!disposition) return 0;

if (!alloced) {
value = xmalloc(alloced = VALUEGROWSIZE);
}

/* Copy value into buffer */
to = value;
left = alloced - 1;
if (*disposition == '\"') {
/* Quoted-string */
disposition++;
while (*disposition && *disposition != '\"') {
if (!--left) {
alloced += VALUEGROWSIZE;
value = xrealloc(value, alloced);
to = value + alloced - left - 2;
}
if (*disposition == '\\') {
disposition++;
if (!*disposition) return 0;
}
*to++ = *disposition++;
}
if (!*disposition) return 0;
}
else {
/* Just a token */
while (*disposition && !isspace(*disposition) &&
*disposition != '(') {
if (!--left) {
alloced += VALUEGROWSIZE;
value = xrealloc(value, alloced);
to = value + alloced - left - 2;
}
*to++ = *disposition++;
}
}
*to = '\0';
return value;
}

/*
* Read and handle a message/partial object from the file 'infile'.
*/
handlePartial(infile, headers, contentParams, boundaries)
FILE *infile;
char *headers;
params contentParams;
struct boundary *boundaries;
{
char *id, *dir, *p;
int thispart;
int nparts = 0;
char buf[1024];
FILE *partfile, *outfile;
int i, docopy;

id = getParam(contentParams, "id");
if (!id) {
warn("partial message has no id parameter");
goto ignore;
}

/* Get directory to store the parts being reassembled */
dir = os_idtodir(id);
if (!dir) goto ignore;

p = getParam(contentParams, "number");
if (!p) {
warn("partial message doesn't have number parameter");
goto ignore;
}
thispart = atoi(p);

if (p = getParam(contentParams, "total")) {
nparts = atoi(p);
if (nparts <= 0) {
warn("partial message has invalid number of parts");
goto ignore;
}
/* Store number of parts in reassembly directory */
sprintf(buf, "%sCT", dir);
partfile = fopen(buf, "w");
if (!partfile) {
os_perror(buf);
goto ignore;
}
fprintf(partfile, "%d\n", nparts);
fclose(partfile);
}
else {
/* Try to retrieve number of parts from reassembly directory */
sprintf(buf, "%sCT", dir);
if (partfile = fopen(buf, "r")) {
if (fgets(buf, sizeof(buf), partfile)) {
nparts = atoi(buf);
if (nparts < 0) nparts = 0;
}
fclose(partfile);
}
}

/* Sanity check */
if (thispart <= 0 || (nparts && thispart > nparts)) {
warn("partial message has invalid number");
goto ignore;
}

/* Create file to store this part */
sprintf(buf, "%s%d", dir, thispart);
partfile = fopen(buf, "w");
if (!partfile) {
os_perror(buf);
goto ignore;
}

/* Do special-case header handling for first part */
if (thispart == 1) {
int skippedfirstbyte = 0;

while (*headers) {
if (*headers == '\n' &&
(!cistrncmp(headers, "\ncontent-", 9) ||
!cistrncmp(headers, "\nmessage-id:", 12))) {
/* Special case, skip header */
headers++;
while (*headers && (*headers != '\n' || isspace(headers[1]))) {
headers++;
}
}
else {
/* First byte of headers is extra newline, don't write it to file */
if (skippedfirstbyte++) putc(*headers, partfile);
headers++;
}
}
docopy = 0;
/* Handle headers in the multipart/partial body */
while (fgets(buf, sizeof(buf), infile)) {
if (*buf == '\n') {
putc('\n', partfile);
break;
}
if (!cistrncmp(buf, "content-", 8) || !cistrncmp(buf, "message-id:", 11)) {
docopy = 1;
}
else if (!isspace(*buf)) {
docopy = 0;
}

if (docopy) fputs(buf, partfile);
while(buf[strlen(buf)-1] != '\n' && fgets(buf, sizeof(buf), infile)) {
if (docopy) fputs(buf, partfile);
}
}
}

/* Copy the contents to the file */
while (fgets(buf, sizeof(buf), infile) &&
!PendingBoundary(buf, boundaries->id, &boundaries->count)) {
fputs(buf, partfile);
}
fclose(partfile);

/* Check to see if we have all parts. Start from the highest numbers
* as we are more likely not to have them.
*/
for (i = nparts; i; i--) {
sprintf(buf, "%s%d", dir, i);
partfile = fopen(buf, "r");
if (partfile) {
fclose(partfile);
}
else {
break;
}
}

if (i || !nparts) {
/* We don't have all the parts yet */
return 0;
}

/* We have everything, concatenate all the parts into a single file */
sprintf(buf, "%sFULL", dir);
outfile = fopen(buf, "w");
if (!outfile) {
os_perror(buf);
return 1;
}
for (i=1; i<=nparts; i++) {
sprintf(buf, "%s%d", dir, i);
partfile = fopen(buf, "r");
if (!partfile) {
os_perror(buf);
return 1;
}
while (fgets(buf, sizeof(buf), partfile)) {
fputs(buf, outfile);
}
fclose(partfile);

/* Done with message part file, delete it */
sprintf(buf, "%s%d", dir, i);
remove(buf);
}

/* Open the concatenated file for reading and handle it */
fclose(outfile);
sprintf(buf, "%sFULL", dir);
outfile = fopen(buf, "r");
if (!outfile) {
os_perror(buf);
return 1;
}
handleMessage(outfile, "text/plain", (struct boundary *)0);
fclose(outfile);

/* Clean up the rest of the reassembly directory */
sprintf(buf, "%sFULL", dir);
remove(buf);
sprintf(buf, "%sCT", dir);
remove(buf);
os_donewithdir(dir);

return 0;

ignore:
ignoreMessage(infile, boundaries);
return 1;
}

/*
* Skip over a message object from the file 'infile'.
*/
ignoreMessage(infile, boundaries)
FILE *infile;
struct boundary *boundaries;
{
char buf[1024];

while (fgets(buf, sizeof(buf), infile) &&
!PendingBoundary(buf, boundaries->id, &boundaries->count));
return 0;
}

/*
* Read and handle a multipart object from the file 'infile'.
*/
handleMultipart(infile, contentType, contentParams, boundaries)
FILE *infile;
char *contentType;
params contentParams;
struct boundary *boundaries;
{
char *id;
char *defaultContentType = "text/plain";
int depth;

/* Components of multipart/digest have a different default content-type */
if (!cistrcmp(contentType, "multipart/digest")) {
defaultContentType = "message/rfc822";
}

if (!(id = getParam(contentParams, "boundary"))) {
warn("multipart message has no boundary parameter");
id="";
}

/* Expand boundaries array if necessary */
if (boundaries->count == boundaries->alloc) {
boundaries->alloc += 20;
boundaries->id = (char **)xrealloc((char *)boundaries->id,
boundaries->alloc * sizeof(char *));
}

/* Add the new boundary id */
boundaries->id[boundaries->count++] = strsave(id);
depth = boundaries->count;

/* Skip over preamble */
ignoreMessage(infile, boundaries);

/* Handle the component messages */
while (boundaries->count == depth) {
handleMessage(infile, defaultContentType, boundaries);
}

/* Skip over postamble */
if (boundaries->count == depth-1) {
ignoreMessage(infile, boundaries);
}

/* Remove any lingering unused description file */
(void) remove(TEMPFILENAME);

return 0;
}

/*
* Handle a text message object from the file 'infile' by saving it to
* the temporary description file.
*/
int handleText(infile, contentEncoding, boundaries)
FILE *infile;
enum encoding contentEncoding;
struct boundary *boundaries;
{
FILE *descfile;
char buf[1024];

descfile = fopen(TEMPFILENAME, "w");
if (!descfile) {
os_perror(TEMPFILENAME);
ignoreMessage(infile, boundaries);
return 1;
}

/* Write the file, handling the appropriate encoding */
switch (contentEncoding) {
case enc_none:
case enc_binary:
fromnone(infile, descfile, (char **)0, boundaries->id, &boundaries->count);
break;

case enc_qp:
fromqp(infile, descfile, (char **)0, boundaries->id, &boundaries->count);
break;

case enc_base64:
from64(infile, descfile, (char **)0, boundaries->id, &boundaries->count);
break;
}

fclose(descfile);
return 0;
}

/*
* Read a message object from 'infile' and save it to a file.
*/
saveToFile(infile, contentType, contentParams, contentEncoding,
contentDisposition, contentMD5, boundaries)
FILE *infile;
char *contentType;
params contentParams;
enum encoding contentEncoding;
char *contentDisposition, *contentMD5;
struct boundary *boundaries;
{
FILE *outfile = 0;
int binaryoutput;
char *outputmd5;
char *fname;

/* Find an appropriate filename and create the output file */
binaryoutput = (contentEncoding == enc_base64 ||
contentEncoding == enc_binary);
fname = getDispositionFilename(contentDisposition);
if (!fname) fname = getParam(contentParams, "name");
outfile = os_newtypedfile(fname, contentType, binaryoutput);
if (!outfile) {
ignoreMessage(infile, boundaries);
return 1;
}

/* Write the file, handling the appropriate encoding */
switch (contentEncoding) {
case enc_none:
case enc_binary:
fromnone(infile, outfile, &outputmd5, boundaries->id, &boundaries->count);
break;

case enc_qp:
fromqp(infile, outfile, &outputmd5, boundaries->id, &boundaries->count);
break;

case enc_base64:
from64(infile, outfile, &outputmd5, boundaries->id, &boundaries->count);
break;
}
rewind(outfile);

/* Check the MD5 digest if it was supplied */
if (contentMD5) {
if (strncmp(outputmd5, contentMD5, strlen(outputmd5)) != 0) {
os_warnMD5mismatch();
}
}
free(outputmd5);

fclose(outfile);
return 0;
}


END_OF_FILE
fi
if test -f 'mpack-1.0/macnapp.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macnapp.h'\"
else
echo shar: Extracting \"'mpack-1.0/macnapp.h'\" \(20490 bytes\)
cat >'mpack-1.0/macnapp.h' <<'END_OF_FILE'
/* mac_napp.h -- general mac application library header
*
* (C) Copyright 1990, 1991 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.
*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*

* - Trouble opening window in init proc of other window
*/

#ifdef THINK_C
#define QD(x) (x)
#ifndef NULL
#define NULL 0
#endif
#else
#define QD(x) (qd.x)
#include <MacTypes.h>
#include <Quickdraw.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <MemoryMgr.h>
#include <Menus.h>
#include <OSUtils.h>
#include <TextEdit.h>
#include <Dialogs.h>
#endif

/* implicit void * types.
*/
typedef void **HANDLE;
typedef void *PTR;

/* dual pascal/C strings
*/
typedef unsigned char PCstr;
#define C(str) ((char*)(str) + 1)
#define P(str) ((unsigned char*)(str))

/* SBYTE is supplied for non-char signed bytes.
*/
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef char SBYTE;

/* useful macros:
*/
#define ABS(x) ( (x) < 0 ? -(x) : (x) )
#define SGN(x) ( (x) < 0 ? -1 : 1 )
#ifndef MIN
#define MIN(m,n) ( (n) < (m) ? (n) : (m) )
#define MAX(m,n) ( (n) > (m) ? (n) : (m) )
#endif
#define HIBYTE(x) ( (BYTE) ((x) >> 8) )
#define LOBYTE(x) ( (BYTE) (x) )
#define HIWORD(x) ( (WORD) ( (x) >> 16) )
#define LOWORD(x) ( (WORD) (x) )

/* all window/menu procedures return short integers (see defines below)
*/
typedef short (*na_menup)(struct na_win *, WORD, WORD);
typedef short (*na_mousep)(struct na_win *, Point, short, short);
typedef short (*na_ctrlp)(struct na_win *, Point, short, short, ControlHandle);
typedef short (*na_activep)(struct na_win *, Boolean);
typedef short (*na_closep)(struct na_win *);
typedef short (*na_updatep)(struct na_win *, Boolean);
typedef short (*na_keyp)(struct na_win *, long, short);
typedef short (*na_cursorp)(struct na_win *, Point);
typedef short (*na_miscp)(struct na_win *, EventRecord *);
typedef short (*na_idlep)(struct na_win *);
typedef short (*na_taskp)(struct na_win *);
typedef short (*na_resizep)(struct na_win *, Point, Rect *);
typedef short (*na_openp)(short, AppFile *, FSSpec *);
typedef short (*na_initp)(struct na_win *, long *);
typedef struct na_win {
long flags; /* flags indicating various window settings (see below) */
short delay; /* delay between main loop cycles (in ticks) */
short mousepix; /* number of pixels mouse can move until drag starts */
short minw, minh; /* minimum width and height for the window */
short maxw, maxh; /* maximum width and height for the window */
short type; /* current window type (negatives reserved) */
BYTE locks; /* locks on this window structure */
BYTE priority; /* priority if there is a taskp */
RgnHandle cursorRgn; /* cursor region */
RgnHandle uncrsrRgn; /* region cursor isn't in */
WindowPtr pwin; /* window pointer */
struct na_win **next; /* handle to next window in linked list */
struct na_win **task; /* handle to next task in a linked list of active tasks */
struct na_win **child; /* handle to child window list (NULL = no child) */
struct na_win **parent; /* handle to parent window (NULL = toplevel) */
na_menup menup; /* menu proc */
na_mousep mousep; /* mouse proc */
na_ctrlp ctrlp; /* dialog item/control proc */
na_activep activep; /* activate proc */
na_closep closep; /* close proc */
na_updatep updatep; /* update proc */
na_keyp keyp; /* key proc */
na_cursorp cursorp; /* cursor setting proc */
na_miscp miscp; /* miscellaneous event proc (disk/net/app/driver) */
na_idlep idlep; /* idle proc */
na_taskp taskp; /* task proc */
na_resizep resizep; /* resize proc */
long resid; /* storage for window resource id or user data. */
char *data; /* data pointer for user */
} na_win;
typedef struct nate_win {
na_win winp;
TEHandle hTE; /* textedit handle for auto-textedit routines */
ControlHandle hctrl; /* horizontal scroll bar for textedit */
ControlHandle vctrl; /* vertical scroll bar for textedit */
long docwidth; /* width of the document */
short lheight; /* line height of text */
} nate_win;
/* procedures types:
*
* // called for menu events when window is frontmost
* // supercedes global menu function unless NA_NOTPROCESSED is returned.
* // if menuid is 0, the procedure should enable/disable menus appropriately
* // if menuid is 1, the procedure should disable enabled menus appropriately
* short menu(winp, menuid, itemno)
* WORD menuid; // resource id of the menu
* WORD itemno; // item number of the menu item
*
* // called for mouse down/up/move events in the window
* short mouse(winp, p, type, mods)
* Point p; // location of mouse action
* short type; // type of mouse action (see below)
* short mods; // modifier keys
*
* // called for dialog events in dialog windows
* // control events in windows with controls
* // In a dialog window with no key procedure, ESC, command-., return, enter are
* // mapped to iCancel and iOk.
* short control(winp, p, itemHit, mods, ctrlh)
* Point p; // point in window local coords
* short itemHit; // the item/part code clicked
* short mods; // modifier keys
* ControlHandle ctrlh; // handle to the control
*
* // called when window is activated or deactivated
* // close return values may be ignored on a deactivate
* short activate(winp, on)
* Boolean on; // true = activate, false = deactivate
*
* // called when a window close request has been made (close box/close menu item)
* // called when any window function returns NA_REQCLOSE or NA_REQCLOSEALL
* // respond with either NA_CLOSED or NA_NOTPROCESSED
* short close(winp)
*
* // called on update events
* short update(winp, newsize)
* Boolean newsize; // true if r is a new window size
*
* // called on key/autokey events (menu keys are parsed out first)
* short key(winp, c, mods)
* long c; // ASCII value of the key (unless NA_RAWKEY option set)
* short mods; // modifier keys
*
* // called when cursor moves into or out of a window
* // use winp->flags & NA_CURSORON
* // close request return values are ignored.
* // return NA_PROCESSED only when the cursorRgn is changed
* short cursor(winp, p)
* Point p; // point where the cursor is
*
* // This is called for miscellaneous events (disk/network/driver/app1-3)
* short miscp(winp, pevent)
* EventRecord *pevent; // the event
*
* // called every time through the event loop when window active
* short idle(winp)
*
* // called cyclicly with other tasks with each pass through event loop
* // only used when task is installed
* // the task procedure can only close it's own window.
* short task(winp)
*
* // function called to resize the window
* // (parameters similar to GrowWindow function)
* short resize(winp, where, rct)
* Point where;
* Rect *rct;
*
* // function passed to NAinit:
* // should return 0 if OK, and -1 to stop opening files
* short open(message, afile, fspec)
* short message; // either appOpen or appPrint (in SegLoad.h)
* AppFile *afile; // file to open/print (if NULL, use fspec)
* FSSpec *fspec; // file to open/print (if NULL, use afile)
*
* // function passed to NAwindow:
* // returns standard window status
* short init(winp, datap)
* na_win *winp; // pointer to new window structure
* long *datap; // pointer to data passed through NAwindow
*/

/* niftyapp globals */
extern na_win **NAhead; /* handle to the head of the window tree */
extern na_win **NAtask; /* handle to the head of the window task list */
extern na_win **NActask; /* handle to the current task */
extern na_win *NAwin; /* pointer to current window (NULL = no current window) */
extern na_menup NAmenup; /* pointer to default menu procedure */
extern short NAnewitem; /* item number of the new item on the file menu (0 = not avail) */
extern short NAcloseitem; /* item number of the close item on the file menu (0 = not avail) */
extern short NAappleitems; /* the number of items at the top of the apple menu */
extern Boolean NAhasedit; /* true if application has an edit menu */
extern long NAdelay; /* the wait next event delay */
extern SysEnvRec NAsysenv; /* mac system environment */
extern Boolean NAinBack; /* true if application is backgrounded */
extern long NAmousetime; /* time of last mouse up event */
extern short NAlastmouse; /* kind of last mouse event */
extern Cursor NAibeam; /* the ibeam cursor */
extern long NAgestaltBits; /* 0 = gestalt not on system */

/* globals for your convenience */
extern RgnHandle NAfullRgn, NAnullRgn;

/* niftyapp definitions */

/* default resource id for niftyapp windows */
#define NA_CLIPWINDOW 1000
#define NA_DEBUGWINDOW 1001
/* default resource id for menu bar */
#define NA_MBAR 128
/* default item numbers for OK & cancel */
#define iOk 1
#define iCancel 2
/* default resource ids for APPLE, FILE, and EDIT menus */
#define mApple 128
#define mFile 129
#define mEdit 130
/* default item numbers for edit menu */
#define iUndo 1
#define iCut 3
#define iCopy 4
#define iPaste 5
#define iClear 6
#define iSelAll 8
#define iClipboard 9
/* new window positions */
#define NA_HFULLSCN 0x0000
#define NA_HQUARTERSCN 0x0001
#define NA_HHALFSCN 0x0002
#define NA_H3QUARTERSCN 0x0003
#define NA_VFULLSCN 0x0000
#define NA_VQUARTERSCN 0x0004
#define NA_VHALFSCN 0x0008
#define NA_V3QUARTERSCN 0x000C
#define NA_CENTERSCN 0x0000
#define NA_TOPSCN 0x0010
#define NA_BOTTOMSCN 0x0020
#define NA_LEFTSCN 0x0040
#define NA_RIGHTSCN 0x0080
#define NA_STACK 0x0100
#define NA_TITLEOFFSET 0x0200
/* new window flags */
#define NA_PLAINWIN 0x00000000L /* plain window -- no title, simple border */
#define NA_COLORWINDOW 0x00000001L /* allow color in the window */
#define NA_DIALOGWINDOW 0x00000002L /* open as a dialog */
#define NA_TITLEBAR 0x00000004L /* have title bar */
#define NA_GROWBOX 0x00000008L /* have a grow box (enables automatic drawing) */
#define NA_ZOOMBOX 0x00000010L /* have a zoom box */
#define NA_CLOSEBOX 0x00000020L /* have a close box (enables close menu item) */
#define NA_SHADOWBORDER 0x00000040L /* have a shadow border (for dialogs) */
#define NA_DOUBLEBORDER 0x00000080L /* have a double (dialog) border */
#define NA_ROUNDBORDER 0x000000c0L /* have rounded corners and black title bar */
#define NA_CHILDWINDOW 0x00000100L /* open as a child window of current window */
#define NA_NOTVISIBLE 0x00000200L /* do not make window visible on open */
#define NA_BEHIND 0x00000400L /* open window behind current window */
#define NA_HASCONTROLS 0x00000800L /* process/draw/kill controls automatically */
#define NA_HASTASK 0x00001000L /* install window in background task list */
#define NA_USERESOURCE 0x00002000L /* use res parameter as WIND/DLOG/wctb/dctb resource */
#define NA_CURSORON 0x00004000L /* true if application has set the cursor */
#define NA_MODAL 0x00008000L /* set if window/dialog will be modal */
#define NA_DIALOGUPDATE 0x00010000L /* UpdtDialog will be called */
#define NA_DEFBUTTON 0x00020000L /* show default button after init proc */
#define NA_COPYDATA 0x00040000L /* data will by copied by NAwindow */
#define NA_SMARTSIZE 0x00080000L /* window resizes & placements are saved in WIND res */
#define NA_RECENTER 0x00100000L /* don't force size, just recenter window */
#define NA_FORCESIZE 0x00200000L /* when a resource is used, re-size the window anyway */
#define NA_RAWKEY 0x00400000L /* if set, key event fields aren't stripped */
#define NA_HILITECTRLS 0x00800000L /* if set, hilite controls on activate/deactive */
#define NATE_FLAGS 0x0f000000L /* flags reserved for NATE */
#define NA_USER_FLAG1 0x10000000L /* flags reserved for users */
#define NA_USER_FLAG2 0x20000000L
#define NA_USER_FLAG3 0x40000000L
#define NA_USER_FLAG4 0x80000000L
/* niftyapp window types */
#define NA_CLIPTYPE -1
#define NA_DEBUGTYPE -2
/* mouse click types */
#define NA_DOWN1 0
#define NA_UP1 1
#define NA_DOWN2 2
#define NA_UP2 3
#define NA_DOWNN 4
#define NA_UPN 5
#define NA_DRAG 6
#define NA_RELEASE 7
/* return values for window/menu procedures */
#define NA_ALLCLOSED -4 /* all windows are to be destroyed & exit app immediately */
#define NA_REQCLOSEALL -3 /* request to close all windows & exit app */
#define NA_CLOSED -2 /* current window is ready to close (used by closep/taskp) */
#define NA_REQCLOSE -1 /* request to close current window */
#define NA_NOTPROCESSED 0 /* use any default handler available */
#define NA_PROCESSED 1 /* do nothing more */
#define NA_DPROCESSED 2 /* don't do key -> button translation on a dialog */
/* Gestalt bits */
#define NA_HASGESTALT 0x00000001L /* Gestalt available */
#define NA_HASAEVENTS 0x00000002L /* Apple events supported */

/* niftyapp macros */

#define NAunlockWindow(winp) {if (!--(winp)->locks) HUnlock((Handle) GetWRefCon((winp)->pwin));}
#define NAunlockWindowh(winh, winp) {if (!--(winp)->locks) HUnlock((Handle) winh);}
#define NAisDAWindow(pWnd) (( (WindowPeek) pWnd)->windowKind < 0)
#define NAenableMItem(menu, item) EnableItem(GetMHandle(menu), item)
#define NAdisableMItem(menu, item) DisableItem(GetMHandle(menu), item)
#define NAcheckItem(menu, item, c) CheckItem(GetMHandle(menu), item, c)
#define NAgetDHandle(dlg, it, hn) {short ty; Rect r; GetDItem(dlg, it, &ty, (Handle *) (hn), &r);}
#define NAgetDRect(dlg, it, rct) {short ty; Handle hn; GetDItem(dlg, it, &ty, &hn, (rct));}
#define NAsetInum(dlg, it, val) NAsetIText(dlg, it, longtoPCstr(val))
#define NAalert(resid) Alert(resid, NAfilterProc)

/* niftyapp procedures */

/* initialize the Macintosh managers and niftyapp internal variables.
* optionally set up a menu bar & menu procedure.
* Returns 0 if OK, negative if an error occured, 1 if print files requested & app should quit
* short minK; // minimum K needed to execute
* short masters; // number of times to call MoreMasters()
* na_proc *openp; // open file procedure -- called for each application in the startup list
* na_proc *menup; // pointer to a menu procedure (NULL = no menu handling)
* short numapple; // number of apple menu items
* short newitem; // item number of new item
* short closeitem; // item number of close item
*/
short NAinit(short, short, na_openp, na_menup, short, short, short);

/* call the main loop procedure
*/

void NAmainloop(void);

/* create a rectangle based on the screen size
* short position; // see above
*/
Rect *NAscreenrect(short);

/* create a new window structure
* returns window status result, up to the caller to pass on NA_ALLCLOSED
* Rect *rpos; // placement rectangle
* long flags; // flags determining type of window
* char *title; // window title (C string may not be NULL unless NA_USERESOURCE)
* short res; // resource number of WIND/DLOG/wctb/dctb/DITL
* long *initdata; // window data (may be NULL)
* long datasize; // bytes of window data
* na_proc *initp; // procedure to initialize the window functions, etc.
*/
short NAwindow(Rect *, long, char *, short, long *, long, na_initp);

/* add a new task to the task list, given pointer to task procedure, and data size
*/
void NAaddtask(na_taskp, long);

/* standard init procedure for an about box -- stops all background tasks, however */
short NAabout(na_win*, long*);

/* standard button flash procedure used by shell for keypresses */
void NAflashButton(DialogPtr, short);

/* draw the default button */

void NAdefaultButton(DialogPtr);

/* re-calculate cursor region information (after changing winp->cursorRgn) */
void NAcalcCursor(na_win*);

/* this saves a window's dimensions into a 'WIND' resource with appropriate resid */
void NAsaveWin(na_win*);

/* This is available to access window structures other than the current window
* best for looking at parent window or child window(s).
*/
na_win *NAlockWindow(na_win**);

/* This is available, but the user should only call it is severe cases */
short NAcloseWindow(na_win*, short);

/* this is for closing all windows, the user should only call it from main
* usually NAhead is the first parameter.
*/
short NAcloseWindows(na_win**, short);

/* this is for sending an event directly to the misc procedure of all windows.
* usually NAhead is the first parameter.
*/
short NAallWindows(na_win**, EventRecord*);


/* niftyappclip functions:
* NAclipboardMenu: menuid, itemid, 'TEXT' or 'PICT'
* NAclipboard: true = window on, false = window off, 'TEXT' or 'PICT'
*/
void NAclipboardMenu(WORD, WORD, ResType);
void NAclipboard(Boolean, ResType);


/* niftyappdebug function:
*/
void NAdebug(char *, ...);


/* niftyappdialog functions:
*/
/* select a radio button
* returns number from 0 to firstitem - lastitem: the button that's been pressed
* DialogPtr dialog; // the dialog window
* short firstitem; // the itemno of first radio button
* short lastitem; // the itemno of last radio button
* short setting; // the radio button to set (itemno to lastitem)
*/
short NAradioSet(DialogPtr, short, short, short);

/* enable/disable,hilite,show/hide an item in a dialog window */
void NAenableDItem(DialogPtr, short, Boolean);
void NAhiliteDItem(DialogPtr, short, short);
void NAvisibleDItem(DialogPtr, short, Boolean);

/* set/get the item text in a dialog item */
void NAsetIText(DialogPtr, short, PCstr*);
void NAgetIText(DialogPtr, short, PCstr*);

/* filter proc for modal dialogs which handles ESC and command-. */
pascal Boolean NAfilterProc(DialogPtr, EventRecord *, short *);

/* modal loop which uses NAfilterProc */
short NAmodalLoop(na_win*);

/* alert with automatic parameters from a STR# resource
* pass 0 for unused strings. Returns item id of button hit.
* NAalertParam(alert, strlist, str1, str2, str3, str4);
*/
short NAalertParam(short, short, short, short, short, short);


/* NATE (NiftyApp TextEdit) libraries
*/
#define NATEflags (NA_TITLEBAR | NA_GROWBOX | NA_ZOOMBOX | NA_CLOSEBOX \
| NA_HASCONTROLS | NA_HILITECTRLS)
#define NATE_DEFAULT 0x00000000L
#define NATE_READONLY 0x01000000L
#define NATE_NOMOUSE 0x02000000L
#define NATE_NOHSCROLL 0x04000000L
#define NATE_NOVSCROLL 0x08000000L
void NATEinit(na_win*, long, short, Ptr, long); /* winp, flags, horizwidth, data, len */
short NATEinitp(na_win*, long*);
short NATEmousep(na_win*, Point, short, short);
short NATEidlep(na_win*);
short NATEactivep(na_win*, Boolean);
short NATEkeyp(na_win*, long, short);
short NATEmenup(na_win*, WORD, WORD);
short NATEupdatep(na_win*, Boolean);
short NATEctrlp(na_win*, Point, short, short, ControlHandle);
short NATEclosep(na_win*);

void NATEsetscroll(na_win*, Boolean, Rect*, Rect*);
void NATEappend(na_win*, char*, long);

/* Niftyapp file library
*/
#define NA_FNAMELEN 65
short NAsaveData(PCstr*, PCstr*, OSType, OSType);
/* PCstr fname[NA_FNAMELEN];
* PCstr *prompt;
* OSType creator, ftype;
*/

/* PC, C string libraries:
*/
#define SetClen(pcstr) (*((pcstr) + *(pcstr) + 1) = '\0')
#define PCstrlen(pcstr) (*(pcstr))
#define Pstrlen(pstr) (* (unsigned char *) (pstr))

void PtoPCstrcpy(PCstr*, char*);
void CtoPCstrcpy(PCstr*, char*);
void PCtoPCstrcpy(PCstr*, PCstr*);
void PtoPCstrncpy(PCstr*, char*, short);
void CtoPCstrncpy(PCstr*, char*, short);
void PtoPCstrcat(PCstr*, char*);
void CtoPCstrcat(PCstr*, char*);
PCstr *PtoPCstr(char*);
PCstr *CtoPCstr(char*);
void SetPlen(PCstr*);
PCstr *longtoPCstr(long);
END_OF_FILE
fi
if test -f 'mpack-1.0/Makefile' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/Makefile'\"
else
echo shar: Extracting \"'mpack-1.0/Makefile'\" \(2442 bytes\)
cat >'mpack-1.0/Makefile' <<'END_OF_FILE'
CFLAGS=$(OPT) $(DEFINES)
OPT=-O


#Uncomment the following line if your system does not have strchr()
#DEFINES=-Dstrchr=index -Dstrrchr=rindex


#Uncomment the following lines to compile on SCO Unix
#OPT=-O2
#DEFINES=-DSCO
#CC=gcc
#LIBS=-lsocket


PACKOBJS = unixpk.o encode.o codes.o magic.o unixos.o string.o \
xmalloc.o md5c.o getopt.o
UNPACKOBJS = unixunpk.o decode.o uudecode.o codes.o unixos.o string.o \
xmalloc.o md5c.o getopt.o

DESTDIR=/usr/local

all: mpack munpack

mpack: $(PACKOBJS)
$(CC) $(CFLAGS) -o mpack $(PACKOBJS) $(LIBS)

munpack: $(UNPACKOBJS)
$(CC) $(CFLAGS) -o munpack $(UNPACKOBJS) $(LIBS)

install: all
-mkdir $(DESTDIR)/bin
-mkdir $(DESTDIR)/man
-mkdir $(DESTDIR)/man/man1
install -s -c -m 755 mpack $(DESTDIR)/bin
install -s -c -m 755 munpack $(DESTDIR)/bin
install -c -m 644 unixpk.man $(DESTDIR)/man/man1/mpack.1
install -c -m 644 unixunpk.man $(DESTDIR)/man/man1/munpack.1

clean:
rm -f *.o mpack munpack

l_pack:
#load unixpk.c encode.c codes.c magic.c unixos.c string.c \
xmalloc.c md5c.c getopt.c

l_unpack:
#load unixunpk.c decode.c uudecode.c codes.c unixos.c string.c \
xmalloc.c md5c.c getopt.c

depend:
grep '^#[ ]*include[ ]*"' *.[ch] | \
sed -e 's/:[^"]*"\([^"]*\)"/: \1/' -e 's/\.c/.o/' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$2 } } \
END { print rec } ' > makedep
echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ed - Makefile < eddep
rm eddep makedep
echo '' >> Makefile
echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
echo '# see make depend above' >> Makefile

# DO NOT DELETE THIS LINE -- make depend uses it


codes.o: xmalloc.h md5.h
decode.o: xmalloc.h common.h
dosos.o: xmalloc.h common.h
dospk.o: version.h xmalloc.h
dosunpk.o: version.h
macmpack.o: macnapp.h macmpack.h version.h
macnapp.o: macnapp.h
macnclip.o: macnapp.h
macndlog.o: macnapp.h
macninit.o: macnapp.h
macnte.o: macnapp.h
macos.o: common.h macnapp.h macmpack.h
macpcstr.o: macnapp.h
md5c.o: md5.h
unixos.o: xmalloc.h common.h
unixpk.o: common.h version.h xmalloc.h
unixunpk.o: version.h
uudecode.o: xmalloc.h common.h

# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above
END_OF_FILE
fi
echo 'End of part 2 (of 6).'
echo 02 >> _shar_private

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:31:31 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 60
Archive-name: mpack-1.0/03

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:

# "End of part 3 (of 6)."


# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'

if test -f 'mpack-1.0/macproj.hqx' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macproj.hqx'\"
else
echo shar: Extracting \"'mpack-1.0/macproj.hqx'\" \(20223 bytes\)
cat >'mpack-1.0/macproj.hqx' <<'END_OF_FILE'
(This file must be converted with BinHex 4.0)

:#Qe`B@0V,R"bEfS!8&*25NY"5%`!!!!!!!!!!$R"2I3!!!!!!3!!!$F6!!!f%`!
!!Uj&!%j"Ad*&5%P14!"139p)390$6dj88Np-8`"139p)33TYF'&MDbj`FQpUF!)
!!!"38Np+5d&)6!%!!&!!!!!!!!"38Np+5d&)6!%!!&!!!!!!!!!!!!!!!!!!!!!
!!!!!!+EmFFB!!!!!!!!j`84"9%%!6N&I8de"8P4659T&!%j"Ae*&3d919%95!%j
"AdC28N0&8dPD43"139p539G,49N!6N&I5%P-594&3e456&-!6N&849p'6%&(8`"
139p98d95AdC-38Fa!%j"Ae9649*I4Na"4c)!6N&I990&8Pp'6%&(-`"139p98d9
5AdB!!!2`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!8!!!!#!!+rZB"h!%S!!!!Q@B%!!!!!!!!)J!!!!!!!!!!!!!!!!!!!#%
!!!J%,Q&cE3G85%P15b"$!LjM"e4)58j,)%-$,Q0`$&0jE@&ZG'9M)%-V+`3ZBh"
`$&0jE@&ZG'9M)%-V+`8ZEQpdC3FJafj[EQA)!Lj[$5!ZEb"$EfjfCA*dCA)#,R)
*9%K*6NXJ8Q9k"5jbFh*M$e*PFfpeFQ0P)%0[F'PPFJ!!!!)"!!!!!#$rr`K)B@e
cG'9b1Xi#LJ+cIrm!c`+c!V3#Z31NIrm"``!!!9S!!$!&!!"%8PC5!'#QD!"JTE3
!B+Ci!'#QA!"JTCJ!!!!!!!!!!!!!!!!!!!!!5BF!k3'c!)!!J!!!5BF!!!!!!!!
EbJ!!'mX!"`#%!0S!PJ%J!3%%6h"PEJ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!46BACP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrm!#!!&!"5
X&J!8V#-!!!Mr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!N8!!!!!!!!!!!!!!!!!!!!!!!!#3!!!!E`!!!
!!!!!!!!!!!!!%%e*688JF'&MDbeeER"KBfX!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%&38%aY8%&,5%!!!!)!!!!!!!!!!!!
!!!!+@%!!#!!!!!J!!!!!!(!"!3!!!!!MC'9QD@jP)(4bG@8J)#!J)#!J-3dMC'9
QD@jP)'CKE(0P)#!J)#!J-!dMC'9QD@jP)(*PHL!J)#!J)#!J-3dMC'9QD@jP)'4
PFQ9k)#!J)#!J-!dMC'9QD@jP)&4)58j,Ae*PHL!J-3d!!!!0!!!!!!!!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!)$!!3!!!!#!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!"!J!$!!!!!`!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J-!"3!!!!3!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!%#!!%!!!!&!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!"!J!b!!!!"J!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3)!%J!!!!!!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!)$!"-!!!!(!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!#!`!8!!!!#!!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J-!'!!!!!N!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!-%!!J!!!!+!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!$"!!#!!!!#`!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J-!&3!!!!!!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!)$!!F!!!!-!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!%"3!,!!!!!!!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J-!%3!!!!!!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!)$!!N!!!!!!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!#!`!+!!!!$3!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`3!$3!!!!i!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!%#!!!!!!!2!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!"!J!c!!!!%!!!!'!!!!!!!!!!!!!!!!!!!!!!!!!
!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3)!$J!!!"%!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!)$!!m!!!!!!!!!B!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!#!`!3!!!!!!!!!PJ!!!kF!!!!E!!!!!!!!!8)!!!
L,J!!#1J!!"#'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J-!&J!!!")!!!"J!!!
!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!%#!"F!!!!!!!!!k!!!$MB!!!#3!!!!!!!!!!*f!!"2lJ!!**!!!!!GdJ!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!%#!!`!!!!!!!!2!!!!%M!!!!&d!!!!!!!!'M)
!!#HN!!!A"!!!'+`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!C!!!!!!!!$QJ
!!!kJ!!!!'!!!!!!!!"P5!!!+[J!!"8!!!!H#!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!`3!'J!!!!!!!!hi!!!"TJ!!!!!!!!!!!!!BUJ!!!DB!!!$!!!!"4!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!-%!"X!!!!!!!!1!!!!"I`!!!!!!!!!!!!!'+S
!!!%Z!!!#L!!!!,B!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!F!!!!!!!!$i!
!!!L%!!!!r!!!!!!!!"XJ!!!VPJ!!'(J!!"X3!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!`3!(3!!!!!!!!j3!!!"X!!!!!!!!!!!!!!C0J!!!a3!!!#d!!!#6!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!-%!"i!!!!!!!!1k!!!$U!!!!!B!!!!!!!!'N!
!!!k`!!!I,!!!#HB!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!I!!!!!!!!$I!
!!!@S!!!!!!!!!!!!!"L1!!!!aJ!!!'!!!!#)!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!`3!)!!!!!!!!!iS!!!"E!!!!!!!!!!!!!!Bm!!!!F3!!!!m!!!"[!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!-%!#%!!!!!!!!2X!!!#,i!!!$m!!!!!!!!'h3
!!$CS!!!C4!!!),S!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!L!!!!!!!!$aJ
!!!kJ!!!!'!!!!!!!!"U8!!!CJJ!!"i!!!!q3!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!-%!#-!!!!!!!!0f!!!!@`!!!!!!!!!!!!!''3!!!!%!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!N!!!!!!!!$pJ!!!Lq!!!!r!!!!!!!!"Z
k!!!hpJ!!'J3!!#&1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`3!*3!!!!!!!"(
)!!!+J!!!!A3!!!!!!!!IFJ!!AB3!!#0m!!!c$J!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!-%!#B!!!!!!!!2k!!!%,3!!!$m!!!!!!!!'pB!!$J`!!!QZ!!!)E)!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!R!!!!!!!!$qJ!!!M#!!!!r!!!!!!!!"[
@!!!i-!!!'N!!!#'b!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`3!+!!!!!!!!!h
`!!!"L!!!!!!!!!!!!!!BMJ!!!-B!!!"J!!!!L!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!-%!#N!!!!!!!!31!!!#1B!!!!B!!!!!!!!(')!!$T%!!!D@!!!)a)!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!$"!!U!!!!!!!!%*!!!!!1VJ!!!"J!!!!!!!!
Fr!!!1h)!!#$3!!!P,!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-%!#X!!!!!!!!
3Z!!!%,3!!!$m!!!!!!!!(8)!!$`3!!!QZ!!!*M3!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!$"!!X!!!!!!!!%+J!!!MU!!!!'!!!!!!!!"dQ!!!leJ!!'R`!!#A3!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`3!,3!!!!!!!"$`!!!3E!!!!2`!!!!!!!!
GT!!!3QS!!"jX!!!T(!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-%!#i!!!!!!!!
3q!!!#UJ!!!$m!!!!!!!!(E)!!%-F!!!HK!!!+A!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!$"!![!!!!!!!!%2J!!!US!!!!r!!!!!!!!"fb!!"$(!!!(S3!!#P`!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`3!-!!!!"-!!!"J!!!!!!!!!!!!!!!!!!!
!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#!$%!!!!!!!!
--!!!!83!!!!!!!!!!!!!&U3!!"`+!!!([!!!$@S!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!#!`!'!!!!)*A%ahK!!!!!!!!MD@jME(9NC5!m6@&M5'9KC'9bFci!!!!
!&J+J!!3$B!)R!U)#,!0K!hpb33!!!!!!!!"J!!!!F!!!!!!!!!"3!!!!)!!J2c`
!!DR`"Hir2!!"UI!'!Mmm!!'Tm!B@2c`!!DR`"M)r2!!"UI!'D$mm!!'Tm!D)2c`
!!DR`"USr2!!"UI!'bMmm!!'Tm!P%2c`!!DR`!!!!"!!!!!!!!!!%!!!!!!!!!!3
!!!!!!!!!"!!!!!!!!!P@!!!!#J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"3
!!!!!3RJ+5Th16VS!D%kk!(JX2%P14&K1ZJG14rVraLD-4rVra#D%6VS!J%kk!lC
1ZJJ'6VS!mNkk!,j1ZJ!Q3QG)H2rr5'm!"%KA5(J!!5)krkT1ZJ9H6V8B!#"Y!'a
1N!#Tp#)krjTR#%kk"8K1Y4J!6R94q!THF!"1ZJ6'C`C+N!"R!U"*6R8J1!TiCJi
X2&T26N91ZJE5)!aJ"LC!)#X!)%IkrdJQJ%je,$a%394"6VS'YL"-)RJ*##!%S#j
1ZJGU4rVr-#D%,$a69&*66VS'Q%Ikra`QM#`m4&*&6%kk"SJJ6#!%C`a1ZJ+Z")!
!!!!-C[41qJFd6PErfN(i#4!L6h!JS#j`!G!4@K(5`%(k!"*`"D!Z9Bp)E`!#UCG
1ANje,R*cFQ-!4rS(pLDi#R`JH!TiXI`!!!!!C`K(qJIQ*UJ!&Lmi#S"Q!PL26R9
BMdMRrrJq,`!i8IJ+AQ!+@Bm[#+QP)"qJ3$!(6VS$eQGX4rVqKLD))""Rj#*!5T&
Q,U!TS%NX2%0548a1ZJAHCd`q,`!i)%`J"'F-6VS!fJ5!!!!!$'Ed6VS'JNkk!R`
JH[j)S'N)!!!(CJ5JC+!T6VS#jL*[!$4GL5p*!$C-harr9)p+1!%YC`+TrdjeF!q
Tb9L2)'m!"!a36[PQ$M!J6VS$8QISS#T1ZJ+!,Tp1G8kk"bT1ZJ!16VS'Q%je6VS
((%je)$S(%'B!!$)JH!+QF!c3N!#`Z!+UCL)JH!VXS#8J8#*))KKJ#N(S!!Kd!B3
Bd-*4bIrdN!#)d)PQ!Nje)J#J,L"i#Z`J!D!N)P"2lrr!)%p#U!!5-@N!"!!@S"9
#TdKT!!`J6kRb-KK1ZJ,Z*&M9`63B)KKZ2QFL8N&R%P*"CbC@3@F!!+j53@F!!*K
1G6)Srr41ZJ,mde*1G6)Srr41ZJ,-de*1G6)Srr41ZJ,5dkVrrNje6VS#NM)T!!a
+D3!+CL"83QS38N*QH("MUFP53QEide*1G8kk!T65U3!1de*1G8kk!Uc5U3!1$%,
rr'GLE@K53QB%de*1G82e'!+q8@E-$'%r2'E'8N*Q"JTU!"IrrM)K@%%LH[c3dT'
55Y056R8b+2rd6VS#D0+0dkVrrNje-LMrp%kk!M65MG1Urrj1G8kk!LM5U3!1dSh
6U[rq6RA5MG1Urrj1G82e'!+q8@E`$'%r2'EU#QS!!rrm-L&F35*kr(65NG+Urrk
55M9"rrid[%ja6R8b'%kk!H"&p4J!eGJd''Fb)KKZ*'F18N&Q&$)Srr41ZJ(SB"J
b+2rd6VS"ZQ!1-LMrp%kk!F*J"Nkk!H,5MG156R8L'%kk!GE68Nje)(VlrL!kqrj
+U!!!CbJb+!!SCb)N+!!B@8*$l3!3dqJ!"09C-[`r2%)C%ZJ!26,mUI"43@EX3HJ
!3!5!!!!!3'E'6R8JH[Zk)$VlZR,rG!"+U!!!CaUq+!!pCK3f+!!S5-0R$05$XUJ
!"'8%)LJ!"%(S!%!%J!!!!%"Qe#"kqjBJ8(!3NS$QL6$"jSS!3S!!--*1G5"3FJ!
b'$!B!N"rrqH*3r8B)$34B")L+3!%NSJb`6,m2c`b`M,mUI"4b2rXB$BJ%+"9)%"
b!$)B-"J#3(rrjiP$p4JJ$'P1q3!#CaJd+3!%B!ib%8K`%!!b`M,m6[NLhe()rr!
J1J!+)%"Q!Q%'6Y!!!!!!-$bJ[D0')JJ`2+LITdDbL'F'3IS!,'!J$$J!"!%[C3C
"qJ!LB")-1!!#!5pP"N(k!"KJ"%(k!"j$q[r#)SK1GD#p6RAdq%je6RS!!JM!!!0
1H`!#6R9CMbmm3dp%46m!UD!JAe$i#PiJ#%je+(VkNL*-Np6PJGR"dp41G5KkqRV
#r!"!)M3B'#KkqS,5P%je+(VkCX,m!%!L0"J)NVVkDNje+(Vk9-,m!%!L0"J3dVV
k9%je+(Vk3X,m!%!L0"J%"S%!!!!36R91Z[qL-LN!$%TT!!TQ"NkkrlKJ"%kkrpE
5U3!16R8JAc)B0"L`@&I*rrT+3QIq6[!Jr#"I-KJd',#B9mRrqNT#Crj1m#$k)&m
b'$3BX%*Z#T!!3@d'd%""m!!#-""RrNl`!!!J,`!%,d%!"#)[!!J[A`!%51Fm!#3
!*J&)3X6$+!!U!8K&b-A84%K#3N,!`G##60m!2#)I6R8J,`!%,d%!"#)[!!J[A`!
%51Fa!%kk!*a-h`#-)Kp1G5![!!3[33!%)Lm!##pI!!4)jc%!6VS!I#!"60m!M#)
I6R8J,`!%,d%!"#)[!!J[A`!%51Fa!%kk!#a-h`#-)Kp1G5![!!3[33!%)Lm!##p
I!!4)jc%!6VS!$#!"60m!M#)I6R9+J'SF5S&U$%5!4)&1ZJ!J4)&1G85!6VS!&N5
!4)&1G8U"DJT%J8kk!!C%J%je,M`!!2rrXS"M"L)!F!"1GE#(BJb!`8K!-J"#3%K
!6R@bKf)D,J"#3%K!J-&)3%K(2J")4il"-!G)4c)(6R8N!#B"iSMLLE+(B[L!`F#
(-J2#`#i$5%I1`%K(dSGP#*+#BJ4%J8je8d"Jj(i!8IJ+APQ2,`Br"kQJ)"pR!!#
Z*N"CMbm,UD8Q(b!,+!054qp(8NFk"f!@@Bm["Mm(UD!J(fF!!)K54`D%!!"rrP@
2,`#TTM!I#!!!"@EF82J+AXp&QNGQ(#!$S%![#kQL)"0R!!"D,`ZTNLK6)%ZJ+A!
"6R8J"+%H)!KR!!"#+%J[#kQL)"0R!!!f)%XJ!f!B@Bm["Mm(UD!J(fF!!#*54b"
!)$`!!(rq,`JJ8#*-fF#J,UQM8FhrfTR%*Na`!8je)%Y+4@B%S#01GD!I6R8b2+R
`3rVj%%kk!,!b2+Rb3rVj[%kk!+3b2+Ra3rVjLNkk!*Jb2+Rc3rVjT#"i#RLar!!
!!!"R%#!S!"CR#L!S!"aR&%lk!(41ZJ"`-MbTp%2kqA41qJ"N6VS!B$)mUI4$q[P
b6[S!9#m))'m!##pS!!)!##!k!(CQ!!!m)(J#TR!-d*!!X,J#UQBX6VS!CM)mUI"
1ZJ"#-MbTm8kk!$Sb2+Rb6VS!-M)mUI01ZJ!U-MbTp%kk!#)JAdje-!'K4L4)F!b
K(M!"S%F`r%kj)-N`r%lj)-T1G6!"S8BLD!!)S"m`!5"*S%G1G3!!!!!!!!!!6R8
J1[rdC`3J3%+3!%je!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!$!!!!!!!1!%i!6J"1!!!'!!!CP1`!'CAX!"Q9p!!CPP
F!'CClJ"Q@d`!CPbN!'CGKJ"QAKB!CPq#!'CI[!"QArB!CQ"H!'CL)J"QBQ3!CQ-
D!'CMT!"QC$)!CQ6%!'CPqJ"QCkS!CQI-!'CVX!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!%V1X!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"+cN!!!!!#'!!!
!!)-!!#J!!!%)!$S!4`$+!EX!!3!!!!!!!!!!!)8)8(*[Ch*PFh-!!!#!!!&!!!!
""!!0!!!!!!#q!1X!dJ&)"!40B@YP!!!!!!#q!(i!dJ$E"!T%Efl9G#"0B@YP!!!
!!!#q!!m!dJ"X"!C$B@jMC@`!!!!!!"8!f`!T!8N%#80SC@0V)%&XE(-!!!!!!$%
!f`"&!8N%$80SC@0V)&0[GA*MCA-!!!!!!!"0!0X!B3&*"!T$D'9MDb"1EfjP!!!
!!!"Z!1S!E`%k!!!!!!!!!(S!f`#1!8N%#&9cC5"%DA0V!!!!!!#6!0d!S`&*"3T
4G@PMDb"6Bf&Z!!!!!!!r!"!!X3$-!!!!!!!!!!S!YJ!H!0U)!!!!!!!!)`#f!$F
!fSJ!!!!!!!!+!"!!(J#dL"K6Eh9bBf8JCQPXCA-JG'mJBfpYF'PXC6S!!!!!!#-
!%!!h!+D)%NaTBR*KFQPPFb"dEb"XEf&N1S)!!)`!!!%!!!3!!!!!!%N"03"G!AX
%"P9`C'&dC3!!!!!!53$L!&d"+!3'3f&ZBf9X!!!!!!"*!%m!A3#["!a%Efl9G#"
9F'4KG'8!!!!!!#J"03!m!AX%"%eKDf8!!!!!!!S!6J!H!@#)(8*bD@jR)(4SC5"
`FQpUC@0d)(9`)(4[)'4KG'8rAJ!-JJ!!L!!!!2`!"`!!!!!!$`!-!#0e-)J!!!!
!!!",!!`!A`"1L!!!!!!!!%X!B3"I!-@)!!!!!!!!B`!-!(F!6SJ'9'pdB@`k!!!
!!!![!!`!2`!RL!4'D@aP!!!!!!![!#N!2`"&L!!!!!!!!#m!4`!r!&Q)!QpQ!!!
!!!!J!!!!2`"hL!!!!))!!@J!!!$i!!i!!!!!!-B"!3$D1J!!!!!!!!!!!!!!!!!
!!!!!rrrrrrrrrrqSJb`5!!!!(!!"!!"GB8e"3dd!!!!+E@&MEA"KBfXZB`!!!!'
S!G@3!+J"eC!!U!(9N!!!!!!F!!)!!&T868&$5!!!!3T0B@0)C@&NCA*c!!!!!DE
$f2LQ`pMiTX2Bq!!"!"J!!J!!@Hj69%4*!!!""h0dC'P[,QJ!!!+RX4%1Tl%4$UH
a%3i!!J!D!!)!!&RZ8dPD43!!!!KcDATPAh3ZD!"c!!'Q`pN!TX2C!+E$f3!!!`!
D!!)!!&RZ8e4553!!!3KcG(*TEQFZD!"c!!'QE+UiTQbUZ+CXUVJ!"!!B!!)!!&R
Z3e4C8!!!!3GMG(P`C5jS!!!"U),QkUL#jZUSJZEU!!8!'J!"!!"G98e"3di!!!!
*E@&MEQ&`F#jS!!!"U)+3!&#SJT!!8+L#N!"3!!B!(!!"!!"GB8e"3dd!!!!+E@&
MEA"KBfXZD!!!!!'S`dQVU-0*UkM$5DX!"`!D!!%!!&eK9N958`!!!!PfCA*cD@p
Z,QJ!1J!!!!!!!!!!!!!!!!!!!!!!rrrrrrrrrrqSJb`&!!!!(!!"!!"G98e"3di
!!!!+E@&MEQ0XDA!ZB`!!!!'S!G@3!+J"eC!!U!(9N!!!!!!F!!)!!&T868&$5!!
!!3T0B@0)C@&NCA*c!!!!!DL#jZUSJZEUU),QkJ!"!"S!!3!!A9903801!!!!#@e
KBfjKF(!ZD!!D!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrkM$5D)!!!!D!!%!!&e
K4%9$6`!!!!KNC@0[C'8ZB`!Z!!'S!G@3!+J"eC!!U!(9N!!!!!!F!!)!!&T868&
$5!!!!3T0B@0)C@&NCA*c!$3!!DE$f2LQ`pMiTX2Bq!!"!"J!!J!!@Hj69%4*!!!
""h0dC'P[,QJ!!!+RX4%1Tl%4$UHa%3i!!J!D!!)!!&RZ8dPD43!!!!KcDATPAh3
ZD!"c!!'Q`pN!TX2C!+E$f3!!!`!D!!)!!&RZ8e4553!!!3KcG(*TEQFZD!"c!!'
QE+UiTQbUZ+CXUVJ!"!!B!!)!!&RZ3e4C8!!!!3GMG(P`C5jS!!!"U-0*V+M$5Db
S`dQX!!8!'J!"!!"GB9K038`!!!!*H'eKE'a[BbjS!!!"U-0*SDM$5D'S`dQK!!B
!'J!"!!"GB80268d!!!!)BfpYE@pZ,QJ!!"S!!!!!!!!!!!!!!!!!!!!!!2rrrrr
rrrrrU-0*R3!!!"J!!3!!A@&$6d4&!!!!"f0[C'9c,Q-!!!'S!G@3!+J"eC!!U!(
9N!!!!!!F!!)!!&T868&$5!!!!3T0B@0)C@&NCA*c!$3!!DE$f2LQ`pMiTX2Bq!!
"!"J!!J!!@Hj69%4*!!!""h0dC'P[,QJ!!!+RX4%1Tl%4$UHa%3i!!J!D!!)!!&R
Z8dPD43!!!!KcDATPAh3ZD!"c!!'Q`pN!TX2C!+E$f3!!!`!D!!)!!&RZ8e4553!
!!3KcG(*TEQFZD!"c!!'QE+UiTQbUZ+CXUVJ!"!!B!!)!!&RZ3e4C8!!!!3GMG(P
`C5jS!!!"U-0*V+M$5DbS`dQX!!8!'J!"!!"GB9K038`!!!!*H'eKE'a[BbjS!!!
"U-0*TkM$5DHS`dQR!!B!&J!"!!"GB8e%05i!!!!&E@3e,QJ!'J!!!!!!!!!!!!!
!!!!!!!!!rrrrrrrrrrqS`dQM!!!!'J!"!!"GB8913dm!!!!)C@jMEf4P,Q-!!!!
"U!(9N!#S!G@3!+J"eC!!!!!!(!!#!!"D9%e"3dJ!!!%+6@&M5'9KC'9bF`!d!!'
Q`pMiTX2Bq+E$f2J!!3!B!!)!!&RZ8e4%53!!!3GcG'4TEbjS!!!#Tl%4$UHa%3k
RX4%1!!)!'J!#!!"ClP0*@N8!!!!)FfPkC9pd,QJ!F`!"TX2C!+E$f3#Q`pN!!!-
!'J!#!!"ClP088NN!!!%)Fh4bD@jR,QJ!FcS!!!!!!!!!!!!!!!!!!!!!!2rrrrr
rrrrrU)+'I`!!!"S!!3!!A9903801!!!!#'eKBfjdC5jM!!!!!DJ"eC!!U!(9N!#
S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!!!!"U),QkUL#jZUSJZE
U!!%!'J!"!!"G98e"3di!!!!*E@&MEQ&`F#jS!$S!!!!!!!!!!!!!!!!!!!!!!2r
rrrrrrrrrU),VN3!!!"S!!3!!A9903801!!!!#@eKBfjKF(!ZB`!!!DJ"eC!!U!(
9N!#S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!!!!"TQ6C`+CNfF#
QC0R!!!%!(J!#!!"D98&38%`!!!%03A"`E'9&GQ9ZG(-ZD!!!!U3ak8#N-HP!T$(
T3!!#!"J!!J!!@P9&8&"$!!!""N938%-ZD!"P!!1QC0R!TQ6C`+CNfF!!!`!H!!)
!!&T98&"$9!!!!3a38%08EfpXBQpi,QJ!!!!%TQ6C`+CNfF#QC0R!!!3!(!!#!!"
D98&38%`!!!%,3A"`E'98B@aV,QJ!!!1N-HP!T$(T3+3ak8!!"3!F!!)!!&T98&*
23`!!!3Y3FQpMCA0cCA-ZD!!!!DL#jZUSJZEUU),QkJ!'!"S!!3!!A9903801!!!
!#@eKBfjKF(!ZD!!!!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrkIc0$)!!!!D!!)
!!&T%68&$9!!!!!K0B@08FQ&`F`!Z!!!!!!!!!!!!!!!!!!!!!!!!rrrrrrrrrrq
RjXfi!!!!'J!#!!"D4%e"3e3!!!!*6@&M9(*KF(-b!"S!!!!!!!!!!!!!!!!!!!!
!!2rrrrrrrrrrU)+'R3!!!"`!!3!!A9903803!!!!#QeKBh"MFh4b,Q-!!!!"U!(
9N!#S!G@3!+J"eC!!!!!!(!!#!!"D9%e"3dJ!!!%+6@&M5'9KC'9bF`!!#J!!!!!
!!!!!!!!!!!!!!!!!rrrrrrrrrrqSL9S9!!!!(!!"!!"G98e"3di!!!!+E@&MEQP
ZDA3ZB`!!!!'S!G@3!+J"eC!!U!(9N!!!!!!F!!)!!&T868&$5!!!!3T0B@0)C@&
NCA*c!!!!!DI6GrDRdhIfTp0hpJ!"!"J!!J!!@P988N&3!!!""e4bBA"c,QJ!!!'
QC0R!TQ6C`+CNfF!!!J!H!!)!!&T939"36!!!!3e"F("XC89fC@jdFbjS!!!#T$(
T3+3ak8#N-HP!!!-!'!!#!!"D98938%-!!!%'49"33bjS!'8!!kCNfF#QC0R!TQ6
C`!!%!"i!!J!!@P938%08!!!"$&"33e4[EfaLEhJZD!!!!!5QC0R!TQ6C`+CNfF!
!"3!F!!)!!&T939"36!!!!3Y"F("XC94KE'XZD!!!!k3ak8#N-HP!T$(T3!!'!"`
!!J!!@P938Np$!!!"#e"bEf0PFh0PFbjS!!!"TQ6C`+CNfF#QC0R!!!F!(J!#!!"
D98G&8e3!!!%-4f9cG'&XG%9aG5jS!!!!!DL#jZUSJZEUU),QkJ!)!"S!!3!!A99
03801!!!!#@eKBfjKF(!ZD!!`!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrkKfe*3
!!!!L!!)!!&RU38j653!!!"&"6P0*dA0YB@aX)$3YBRPdC3!D!!!!!!!!!!!!!!!
!!!!!!!$rrrrrrrrrrkM$5DF!!!!B!!%!!&eK68&(53!!!!GYB@GTBbjM!!!"U!(
9N!#S!G@3!+J"eC!!!!!!(!!#!!"D9%e"3dJ!!!%+6@&M5'9KC'9bF`!!!!'Q`pM
iTX2Bq+E$f2J!!3!B!!)!!&RZ8e4%53!!!3GcG'4TEbjS!!!#Tl%4$UHa%3kRX4%
1!!)!'J!#!!"ClP0*@N8!!!!)FfPkC9pd,QJ!FaS!!!!!!!!!!!!!!!!!!!!!!2r
rrrrrrrrrU-0*U!!!!"J!!3!!A@&04$9$!!!!"QeN0@-ZB`!!!!'S!G@3!+J"eC!
!U!(9N!!!!!!F!!)!!&T868&$5!!!!3T0B@0)C@&NCA*c!!!!!DM$5DHS`dQRU-0
*T`!"!"B!!3!!A@&04$8Z!!!!"@eN05jS!"S!!!!!!!!!!!!!!!!!!!!!!2rrrrr
rrrrrU-0*UJ!!!"S!!3!!A@&69&**!!!!#(0dFQPZCbjM!!!!!DJ"eC!!U!(9N!#
S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!!!!"TQbUZ+CXUVLQE+U
i!!%!'!!#!!"ClN08@9!!!!%(Bh4jF'8ZD!!D!!!!!!!!!!!!!!!!!!!!!!$rrrr
rrrrrrkL#KMJ!!!!F!!%!!&e968&$6J!!!!TYB@0ZC'a[CbjM!!!!!DJ"eC!!U!(
9N!#S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!!!!"U),QkUL#jZU
SJZEU!!%!'J!"!!"G98e"3di!!!!*E@&MEQ&`F#jS!"S!!!!!!!!!!!!!!!!!!!!
!!2rrrrrrrrrrU-0*U`!!!"`!!3!!A@&9984&!!!!#R9eC'9MEf4P,Q-!!!!"U!(
9N!#S!G@3!+J"eC!!!!!!(!!#!!"D9%e"3dJ!!!%+6@&M5'9KC'9bF`!!!!'Q`pM
iTX2Bq+E$f2J!!3!B!!)!!&RZ8e4%53!!!3GcG'4TEbjS!!!#Tl%4$UHa%3kRX4%
1!!)!'J!#!!"ClP0*@N8!!!!)FfPkC9pd,QJ!F`!"TQbUZ+CXUVLQE+Ui!!-!'!!
#!!"ClN08@9!!!!%(Bh4jF'8ZD!!!!DM$5DbS`dQXU-0*V!!%!"S!!3!!A@&B68&
-!!!!#AKYB@aXEf-ZD!!!!DM$5D'S`dQKU-0*S3!&!"S!!3!!A@&$6de0!!!!#'0
[E@e[ELjS!!!D!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrkL#N!$M!!!!'!!"!!"
GB8e"3dm!!!!(E@&MEh-ZB`!!!DJ"eC!!U!(9N!#S!G@3!!!!!"`!!J!!@P40380
)!!!"#NeKBdKPB@4PFR-!!!!"TX2Bq+E$f2LQ`pMi!!%!'!!#!!"ClP084%N!!!%
(Fh4ND@mZD!!!!UHa%3kRX4%1Tl%4$J!#!"S!!J!!@Hj659T&!!!!#(0THQ9IG#j
S!(-!!DCXUVLQE+UiTQbUZ!!$!"J!!J!!@Hj$9&P3!!!""f0dHA"P,QJ!!!'Q`pN
!TX2C!+E$f3!!"!!D!!)!!&RZ8e4553!!!3KcG(*TEQFZD!"c!!'N+ibJT#Z-S+3
VM+!!"3!B!!)!!&RZ49*56J!!!3GPFR*ZEbjS!!!"U-0*SDM$5D'S`dQK!!B!'J!
"!!"GB80268d!!!!)BfpYE@pZ,QJ!F`!"U),QkUL#jZUSJZEU!!F!'J!"!!"G98e
"3di!!!!*E@&MEQ&`F#jS!!!"U)+3!&#SJT!!8+L#N!"3!!J!(!!"!!"GB8e"3dd
!!!!+E@&MEA"KBfXZD!!!!!!!!!!!!#m!)!!r!(H)!!!!!!!!!3!!!!J%E@&TEL!
J)!%"!0Sk!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrkL$,")!!!!F!!%!!&eK68&
$63!!!!TYB@0YF'&MDbjM!!!!!DJ"eC!!U!(9N!#S!G@3!!!!!"`!!J!!@P40380
)!!!"#NeKBdKPB@4PFR-!!!!"TX2Bq+E$f2LQ`pMi!!%!'!!#!!"ClP084%N!!!%
(Fh4ND@mZD!!!!UHa%3kRX4%1Tl%4$J!#!"S!!J!!@Hj659T&!!!!#(0THQ9IG#j
S!(-!!DE$f3#Q`pN!TX2C!!!$!"S!!J!!@Hj69&**!!!"#(0dFQPZCbjS!(-!!DC
XUVLQE+UiTQbUZ!!%!"J!!J!!@Hj$9&P3!!!""f0dHA"P,QJ!!!'SJZEUU),QkUL
#jZS!"3!D!!%!!&e968&$6J!!!!PYB@0ZBA"`,QJ!!!'SJT!!8+L#N!"3U)+3!&!
!"J!F!!%!!&eK68&$63!!!!TYB@0YF'&MDbjS!!!!!DM$5DZS`dQVU-0*U`!(!"S
!!3!!A@&@49*6!!!!#ACPFR0TEfiZD!!k!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrr
rrkL$,!8!!!!F!!%!!&e968&$6J!!!!TYB@0ZBfaTF#jM!!!!!DJ"eC!!U!(9N!#
S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!!!!"U),QkUL#jZUSJZE
U!!%!'J!"!!"G98e"3di!!!!*E@&MEQ&`F#jS!"S!!!!!!!!!!!!!!!!!!!!!!2r
rrrrrrrrrU-0*SJ!!!"S!!3!!A@&%4802!!!!#'4PBfpNC5jM!#i!!DJ"eC!!U!(
9N!#S!G@3!!!!!"`!!J!!@P40380)!!!"#NeKBdKPB@4PFR-!0!!"TX2Bq+E$f2L
Q`pMi!!%!'!!#!!"ClP084%N!!!%(Fh4ND@mZD!!!!UHa%3kRX4%1Tl%4$J!#!"S
!!J!!@Hj659T&!!!!#(0THQ9IG#jS!(-!!DE$f3#Q`pN!TX2C!!!$!"S!!J!!@Hj
69&**!!!"#(0dFQPZCbjS!(-!!DCXUVLQE+UiTQbUZ!!%!"J!!J!!@Hj$9&P3!!!
""f0dHA"P,QJ!!!'S`dQXU-0*V+M$5D`!"3!D!!%!!&eK@%e"6!!!!!PiE@&XE'p
M,QJ!!!'S`dQKU-0*SDM$5D%!"J!D!!%!!&eK3dp063!!!!KMEfeYEfiZD!!!C@j
d,8&hBA*P0J!!!!!H3@0MCA"d)&*PE@pdC5")D@GS6'9fC@a&GQ9ZG(-e!!!!!"&
6G'&dD@pZCA*j,8&hBA*P0!!!!!!@9A0P)&4PH(4&C'Pd)&0PFRCTBf9c-`!!!!!
!-J!!!3!!!$F6!!!f%`!!!Ui!5AL%#H`!!!!F!N)!%NK"8dJ!!!#D@Np143!!!+C
,58j%!!!!XPG-6d-!!!#q58j%@!!!!-T$6d4&!!8!eN4"9%%!!!%H8e458`!!!5T
%8N9-!!!"0P0C69-!!!&#3dj'4`!$!8j659T&!!!"IN4#8e3!!!'+4%*A8`!!!CC
$8N9-!!-"SN4#98F!!`(58da69!!!!J*@6da6!!!#$NCA58i!!!)D!!%!!!!!!!!
!5AJ3!!$rr`!!(Jm!5AJ!!!$rr`!!"-F!5AJB!!$rr`!!!r3!5AJ8!!$rr`!!"Um
!5AJ%!!$rr`!!%r%!5AIm!!)!6!!!&&8!5AGX!!-!23!!&&d!5AH!!!3!@3!!&'8
!5AGm!!8!+!!!&'d!5AG`!!(rra3!&(8!5AI-!!$rr`!!(Fm!5AIi!!$rr`!!(G-
!5AI`!!$rr`!!(GF!5AId!!$rr`!!(GX!5AIX!![rr`!!"!!!5AJ)%E3!"J!!"*d
!5AIJ#[i!&!!!%l-!5AIFI1F!(!!!"MX!5AIBrrm!*J!!"Ld!5AJ-!)$rr`!!"L8
!5AI8!)$rr`!!%pF!5AI3!!,rr`!!(Gm!5AG%!!2rr`!!(H-!5AG!!!6rr`!!(HF
!5AG)!!Arr`!!(HX!5AG8!!,rr`!!(Hm!5AGJ!!2rr`!!(I-!5AG-!!6rr`!!(IF
!5AFi!!Arr`!!(IX!5AFJ!!$rr`!!(Im!5AIN!)$rr`!!"+-!5AI%!)$rr`!!"LN
!5AF`"@eVB@KX$5!ZEb"$EfjfCA*dCA)(9%K*6NXJ3`P85%P15b"5CAS"1a41D@C
dH@&`F#"*EQPdD@&XDATPFJj1D@CdH@&`F#"QD@aPF`a0B@PZ)("bEfGbB@d58h4
KEQ4KFQ3J6'PLFQ&bD@9cBC8:
END_OF_FILE
fi
if test -f 'mpack-1.0/macnte.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macnte.c'\"
else
echo shar: Extracting \"'mpack-1.0/macnte.c'\" \(11701 bytes\)
cat >'mpack-1.0/macnte.c' <<'END_OF_FILE'
/* macnTE.c -- TextEdit Utilities for nifty application library
*
* (C) Copyright 1990-1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.
*
* Author: Christopher J. Newman
* Message: This is a nifty program.

*/

#include "macnapp.h"
#ifndef THINK_C
#include <Fonts.h>
#include <Scrap.h>
#include <ToolUtils.h>
#endif

#define DOCWIDTH 2047
#define teinfo ((nate_win *)winp)

/* prototypes for private procedures */
static pascal void vscroll(ControlHandle, short);
static pascal void hscroll(ControlHandle, short);

/* initialize a premade window as a TextEdit window with options
*/
#ifdef __STDC__
void NATEinit(na_win *winp, long flags, short docwidth, Ptr data, long len)
#else
void NATEinit(winp, flags, docwidth, data, len)
na_win *winp;
long flags;
short docwidth;
Ptr data;
long len;
#endif
{
Rect rtemp, vtemp;

winp->flags = (winp->flags & ~NATE_FLAGS) | flags;
if (!docwidth) docwidth = DOCWIDTH;
teinfo->docwidth = docwidth;
rtemp = winp->pwin->portRect;
vtemp = rtemp;
if (!(flags & NATE_NOHSCROLL)) {
vtemp.right = vtemp.left + docwidth;
}
if (!(flags & NATE_READONLY)) {
winp->keyp = NATEkeyp;
}
if (!(flags & NATE_NOMOUSE)) {
winp->mousep = NATEmousep;
winp->idlep = NATEidlep;
}
winp->menup = NATEmenup;
winp->activep = NATEactivep;
winp->updatep = NATEupdatep;
winp->ctrlp = NATEctrlp;
winp->closep = NATEclosep;
winp->cursorRgn = NewRgn();
teinfo->vctrl = teinfo->hctrl = NULL;

TEAutoView(true, teinfo->hTE = TENew(&vtemp, &rtemp));
if (len > 0 && data != (Ptr) NULL) {
TESetText(data, len, teinfo->hTE);
TESetSelect(0, 0, teinfo->hTE);
}
teinfo->lheight = (*teinfo->hTE)->lineHeight;
}

/* initialize a new TextEdit window
*/
short NATEinitp(winp, datap)
na_win *winp;
long *datap;
#ifndef THINK_C
#pragma unused (datap)
#endif
{
NATEinit(winp, winp->flags, 0, NULL, 0);

return (NA_PROCESSED);
}

/* set the controls in the TextEdit window correctly
*/
#ifdef __STDC__
void NATEsetscroll(na_win *winp, Boolean moved, Rect *hrect, Rect *vrect)
#else
void NATEsetscroll(winp, moved, hrect, vrect)
na_win *winp;
Boolean moved;
Rect *hrect;
Rect *vrect;
#endif
{
short vmax, vvalue, hmax, hvalue;
TEPtr te = *teinfo->hTE;
ControlHandle vctrl, hctrl;

vmax = te->nLines + (*(*te->hText + te->teLength - 1) == '\015' ? 1 : 0)
- (te->viewRect.bottom - te->viewRect.top) / teinfo->lheight;
hmax = (short) teinfo->docwidth - (te->viewRect.right - te->viewRect.left);
if (vmax < 0) vmax = 0;
if (hmax < 0) hmax = 0;
vvalue = (te->viewRect.top - te->destRect.top) / teinfo->lheight;
hvalue = te->viewRect.left - te->destRect.left;
if (!(winp->flags & NATE_NOVSCROLL)) {
if (teinfo->vctrl == (ControlHandle) NULL) {
teinfo->vctrl = NewControl(winp->pwin, vrect, "\p", true, vvalue, 0, vmax,
scrollBarProc, 0);
if (winp->pwin != FrontWindow()) HiliteControl(teinfo->vctrl, 255);
} else {
if (vvalue < 0) vvalue = 0;
if (vvalue > vmax) vvalue = vmax;
SetCtlMax(vctrl = teinfo->vctrl, vmax);
SetCtlValue(vctrl, vvalue);
if (moved) {
MoveControl(vctrl, vrect->left, vrect->top);
SizeControl(vctrl, vrect->right - vrect->left,
vrect->bottom - vrect->top);
ShowControl(vctrl);
}
}
}
if (!(winp->flags & NATE_NOHSCROLL)) {
if (teinfo->hctrl == (ControlHandle) NULL) {
teinfo->hctrl = NewControl(winp->pwin, hrect, "\p", true, hvalue, 0, hmax,
scrollBarProc, 0);
if (winp->pwin != FrontWindow()) HiliteControl(teinfo->hctrl, 255);
} else {
if (hvalue < 0) hvalue = 0;
if (hvalue > hmax) hvalue = hmax;
SetCtlMax(hctrl = teinfo->hctrl, hmax);
SetCtlValue(hctrl, hvalue);
if (moved) {
MoveControl(hctrl, hrect->left, hrect->top);
SizeControl(hctrl, hrect->right - hrect->left,
hrect->bottom - hrect->top);
ShowControl(hctrl);
}
}
}
}

/* track procedure for the vertical scroll bar
*/
static pascal void vscroll(ctrl, part)
ControlHandle ctrl;
short part;
{
short amount, value, max, lh;
na_win *winp;
TEHandle hTE;

if (part == 0) return;
winp = * (na_win**) GetWRefCon((*ctrl)->contrlOwner);
hTE = teinfo->hTE;
value = ((*hTE)->viewRect.bottom - (*hTE)->viewRect.top) /
(lh = teinfo->lheight);
switch (part) {
case inUpButton:
amount = -1;
break;
case inDownButton:
amount = 1;
break;
case inPageUp:
amount = - value;
break;
case inPageDown:
amount = value;
break;
}
if ((amount += (value = GetCtlValue(ctrl))) < 0) amount = 0;
if (amount > (max = GetCtlMax(ctrl))) amount = max;
SetCtlValue(ctrl, amount);
TEScroll(0, (value - amount) * lh, hTE);
}

/* track procedure for the horizontal scroll bar
*/
static pascal void hscroll(ctrl, part)
ControlHandle ctrl;
short part;
{
short amount, value, max;

if (part) {
TEHandle hTE = (* (nate_win**) GetWRefCon((*ctrl)->contrlOwner))->hTE;

value = (*hTE)->viewRect.right - (*hTE)->viewRect.left;
switch (part) {
case inUpButton:
amount = -6;
break;
case inDownButton:
amount = 6;
break;
case inPageUp:
amount = - value;
break;
case inPageDown:
amount = value;
break;
}
if ((amount += (value = GetCtlValue(ctrl))) < 0) amount = 0;
if (amount > (max = GetCtlMax(ctrl))) amount = max;
SetCtlValue(ctrl, amount);
TEScroll(value - amount, 0, hTE);
}
}

/* activate procedure for TextEdit
*/
#ifdef __STDC__
short NATEactivep(na_win *winp, Boolean on)
#else
short NATEactivep(winp, on)
na_win *winp;
Boolean on;
#endif
{
if (on) {
TEActivate(teinfo->hTE);
} else {
TEDeactivate(teinfo->hTE);
}

return (NA_NOTPROCESSED);
}

/* Update procedure for textedit window
*/
#ifdef __STDC__
short NATEupdatep(na_win *winp, Boolean newsize)
#else
short NATEupdatep(winp, newsize)
na_win *winp;
Boolean newsize;
#endif
{
TEHandle hTE = teinfo->hTE;


WindowPtr window = winp->pwin;

Rect prect, vrect, hrect, drect;

prect = window->portRect;
EraseRect(&prect);
hrect = vrect = prect;
vrect.top--;
hrect.left--;
vrect.left = ++vrect.right - 16;
hrect.top = ++hrect.bottom - 16;
vrect.bottom -= 14;
hrect.right -= 14;
InsetRect(&prect, 4, 4);
prect.right -= 15;
if (!(winp->flags & NATE_NOHSCROLL)) prect.bottom -= 15;
prect.bottom -= (prect.bottom - prect.top) % teinfo->lheight;
if (newsize) {
drect = (*hTE)->viewRect = prect;
drect.right = drect.left + (short) teinfo->docwidth;
(*hTE)->destRect = drect;
RectRgn(winp->cursorRgn, &prect);
OffsetRgn(winp->cursorRgn, -window->portBits.bounds.left,
-window->portBits.bounds.top);
TECalText(hTE);
TESelView(hTE);
if (teinfo->hctrl != (ControlHandle) NULL) HideControl(teinfo->hctrl);
if (teinfo->vctrl != (ControlHandle) NULL) HideControl(teinfo->vctrl);
}
TEUpdate(&prect, hTE);
if (newsize) NATEsetscroll(winp, true, &hrect, &vrect);

return (NA_NOTPROCESSED);
}

/* control processing procedure for TextEdit
*/
#ifdef __STDC__
short NATEctrlp(na_win *winp, Point p, short part, short mods, ControlHandle ctrl)
#else
short NATEctrlp(winp, p, part, mods, ctrl)
na_win *winp;
Point p;
short part;
short mods;
ControlHandle ctrl;
#endif
#ifndef THINK_C
#pragma unused (mods)
#endif
{
short value;

if (part) {
value = GetCtlValue(ctrl);
switch (part) {
case inThumb:
part = TrackControl(ctrl, p, (ProcPtr) NULL);
if (part && (value -= GetCtlValue(ctrl))) {
TEHandle hTE = teinfo->hTE;

if (ctrl == teinfo->vctrl) {
TEScroll(0, value * teinfo->lheight, hTE);
} else if (ctrl == teinfo->hctrl) {
TEScroll(value, 0, hTE);
}
}
break;

default:
(void) TrackControl(ctrl, p,
(ProcPtr) (ctrl == teinfo->vctrl ? vscroll : hscroll));
break;
}
}

return (NA_PROCESSED);
}

/* idle procedure for TextEdit
*/
short NATEidlep(winp)
na_win *winp;
{
TEIdle(teinfo->hTE);

return (NA_PROCESSED);
}

/* key press procedure for TextEdit
*/
#ifdef __STDC__
short NATEkeyp(na_win *winp, long c, short mods)
#else
short NATEkeyp(winp, c, mods)
na_win *winp;
long c;
short mods;
#endif
{
if (!(mods & cmdKey)) {
ObscureCursor();
TEKey(c, teinfo->hTE);
NATEsetscroll(winp, false, (Rect*) NULL, (Rect*) NULL);
}

return (NA_PROCESSED);
}

/* an edit menu handler for TextEdit
*/
#ifdef __STDC__
short NATEmenup(na_win *winp, WORD menuid, WORD itemno)
#else
short NATEmenup(winp, menuid, itemno)
na_win *winp;
WORD menuid, itemno;
#endif
{
MenuHandle mh = GetMHandle(mEdit);
TEHandle hTE = teinfo->hTE;
TEPtr pte;
short status = NA_NOTPROCESSED;

switch (menuid) {
case 0:
pte = *hTE;
if (pte->selStart != pte->selEnd) {
EnableItem(mh, iCopy);
if (!(winp->flags & NATE_READONLY)) {
EnableItem(mh, iCut);
EnableItem(mh, iClear);
}
} else {
DisableItem(mh, iCopy);
if (!(winp->flags & NATE_READONLY)) {
DisableItem(mh, iCut);
DisableItem(mh, iClear);
}
}
EnableItem(mh, iSelAll);
if (!(winp->flags & NATE_READONLY)) {
EnableItem(mh, iPaste);
}
break;

case mEdit:
switch (itemno) {
case iCut:
TECut(hTE);
goto DOSCRAP;

case iCopy:
TECopy(hTE);
DOSCRAP:
ZeroScrap();
TEToScrap();
goto EDITDONE;

case iPaste:
TEFromScrap();
TEPaste(hTE);
goto EDITDONE;

case iClear:
TEDelete(hTE);
goto EDITDONE;

case iSelAll:
TESetSelect(0, 32767, hTE);
TESelView(hTE);
EDITDONE:
status = NA_PROCESSED;
NATEsetscroll(winp, false, (Rect*) NULL, (Rect*) NULL);
break;
}
default:
DisableItem(mh, iSelAll);
break;
}

return (status);
}

/* mouse procedure for TextEdit
*/
#ifdef __STDC__
short NATEmousep(na_win *winp, Point p, short type, short mods)
#else
short NATEmousep(winp, p, type, mods)
na_win *winp;
Point p;
short type;
short mods;
#endif
{
TEHandle hTE = teinfo->hTE;

if (!PtInRect(p, &(*hTE)->viewRect)) return (NA_PROCESSED);
if (type == NA_DOWN1 || type == NA_DOWN2 || type == NA_DOWNN) {
TEClick(p, mods & shiftKey ? true : false, hTE);
NAmousetime = TickCount();
NAlastmouse++;
}

return (NA_PROCESSED);
}

/* close procedure for TextEdit
*/
short NATEclosep(winp)
na_win *winp;
{
TEDispose(teinfo->hTE);

return (NA_CLOSED);
}

/* append text at the end of a TextEdit window
*/
void NATEappend(winp, data, len)
na_win *winp;
char *data;
long len;
{
TEHandle hTE = ((nate_win*) winp)->hTE;

TESetSelect(32767, 32767, hTE);
TEInsert(data, len, hTE);
TESelView(hTE);
NATEsetscroll(winp, false, (Rect*) NULL, (Rect*) NULL);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/macrsrc.hqx' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macrsrc.hqx'\"
else
echo shar: Extracting \"'mpack-1.0/macrsrc.hqx'\" \(13600 bytes\)
cat >'mpack-1.0/macrsrc.hqx' <<'END_OF_FILE'
(This file must be converted with BinHex 4.0)

:$fe`B@0V,R"bEfSZFR0bB`"bFh*M8P0&4!!!!!!!!!!!*ZK6U3!!!!!"!!!!)l`
!!#+m!!!$,!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$fe`B@0V,R"
bEfSZFR0bB`)!!!"bFh*M8P0&4!%!!'3!!(*cFQ058d9%!3!!C!!!!!!!!!!!!!!
!!!!!!!!!!!!!T[abb`!!!!!!!#ES!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!(!!JJ!!!!!!!!!!rrrq!34&C'Pd"&9ZC'm!@J!!!5d!!!!!!d0
eG!"B!!!%3fp`H3"$!!!&8'&cG'8!9J!!"80XC@&b!!!!!!%Y!!!!!!T6C@aPBh3
J3@aX!%%!!!j6D'ph)%0XDA"LEf&bC!!!!!!!!!!!#!!$!)!!J3##!!!!&J!S!#J
!m!%B!!J!!!%!!!!!!!!!!!!!!!!F!#J!!!!b!5`!#!!!!3!!!!!!#@0XDA"LEf&
bC!!!!!G"8&"-!!!!!!!!3!!!I$j80QfU9RCS'R!13!,rri!"X!f(cB!"Ki'!!Ir
rrRrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrm!!!%!$rrq!!J!!`!)!!+
!#Im#3!N"JL!*I8)3#3(Mq!Pi)!J*!#!)#AqJ#!N!)!J*I#!)#3(J#!Pq-!J*'!`
)#5!##!R!!BJ*!!")#rrrk!S!!#J+m!'S#J!"U!VMiDJ+!!!S#J2`+!S!!#J+!q!
S#J!!+![rrqJ)!!!)#!!!#!rrrrJ2rrm!$rrrJ!rrrm!2rrrJ$rrrm!rrrrJ2rrr
i$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrr
i$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrr
i$rrrq!!!!!G849K8!!%!!!!"!!!!!!"rm!rq3"!)!P*3#1*98!ML99!)iP*3#%*
!&q[k54JD5P8J"%*9`!0#53!!`NB!!'*)!!!5F!!!$N!!!!,rrrrrJ!!!!E`!!$f
!!!!P[!!!*B!!!#@!!!!pJ"r`!B!!!!'!(r`"J!!!!B!Ii!'!!!!"J!!!!B!!!!(
rrrrrrrJIrrri(rrrq"rrrrJIrrri(rrrq"rrrrrrrrrrrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrm!!!!U!#J!+!$8!@F
!"!!!!3!!!!!!!)%54'9MEf4P)%9YB@PX)%CTE'9c!!!!!!!!$J"`!(i""!'f!)0
993!!!!!!6J!$!!!!!!"b!1N!KJ%P"!*25`!!!!!!#!!-!#J!,#!#!!)!!!!!!!N
!4`!G!58)$Ne`B@0V)(GKFQjTEQFk!!!!!!!R!%F!CJ%P#!*H-!!!!!Fr2cmr!!)
!!!!"!!rrrJ!)!!-!#IrbJ!N!%N!*59)J#995%!P98rJ*59!)#3!3#!NNN!!)#99
3#!P98!J**G!)#3B`#!PB$!J*B!))#F!"L!N!!%J,rrrS#J!!+!V`!DJ+!!'S#Z2
KU!S!!#J+!r!S#J!!+!S$i#J+!!!S#rrrk!J!!!J)!!!)$rrrq!rrr`!2rrq!$rr
r`!rrrq!2rrr`$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rr
rq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rr
rq!rrrrJ2rrri$rrrq!rrrrJ2rrri!!!!3$rJ)$!T+#Um+S3T"#!%*+4UTUUPj+H
J"CrjN!!*S!ArrcrJ2r!rq$rm2r`rr$rm2rarr[rrrrrrrrrrrrrrrrrr!!!!3$r
J)$!J+#qm)!3[p#!%,m4J"UrPi!HJ"CrjN!!*S!ArrcrJ2r!rq$rm2r`rr$rm2ra
rr[rrrrrrrrrrrrrrrrrr!!!!'!!I!&)"2`''!!%!!!!!!!!!!!##!!!!!!!!!4S
!$!!!!!!!K!$D!*B")!3%8f&fC3!!!!!!RJ$D!,!")!3'3f&ZBf9X!!!!!!#)!!i
!Q!$&L!K6BACP)'&c1J!!!!!!(3$)!$%",S!!!!!!!!!i!0S!5J%J"!9&DQ9MG!!
!!!!!!&)!fJ"N!5!%"84bDACP!!!!!!!!R3!4!+d!`K!!!!!!!!!G!!i!I`$&J!!
!!!!!!0X!QJ$V!0F3"6B`-$!`!!!!!!!![!"-!-`"(4!!!!!!!!%&!!m"&`#U"44
"C'3JC'9cBh*TF(4TEfiJCQPXC3!!!!!![!!1!-`!5BJ)8h9LDQ9MG$S!!!!!!0X
!$`$q!*@))NeKH'PYG@dJ8'&bG#"6DATP1JdSD@iJBfKKFQ&MG'9bFbN!!!"[!)%
!!!!!!!!!!2rrrjF%4QPXC3a&EQ0[C'8J4QPXCFN!43!!%N4PBfpNC5"0B@PX)%C
TE'9cb3"%!!!",3!!!!!26h"PEL"8CAKd)%CTE'A*!%m!!!9$E'pcC3"A!!!",3!
!!!!%8A9TG!"4!!!!!!!!6!!$!!!!!!"b!1N!KJ%P"!*25`!!!!!!#3"(!"d"*3J
-6A"KBfXJCA*bEh)k!!!!!!!R!%F!CJ%P#!*H-!!!!!!!#J!+!#S!+L!#!!!!!!"
D!!)!!!!!!%d!U!"K!2N%#%jPGb"1B@eP!!!!!!"0!%-!B3#8"!G5CA"XB@0PC3!
!!!!!$3!H!$m"%BJG9'KP)'CTE'8JdPi`db"KE(*PB@4j)'9iDA0dFbi!!!!!#&4
&@&4dG(Kd!!!!#%G*4QC#EhT[!!!!#%T348G+9PG5!!!!'JP'D@aP)&4jF'986N&
0"d0bC@&dEh*86N&0!!!!$J"q!'F!k3'@!)4993!!!!!!$J"`!(i""!'f!)9993!
!!!!!'!"4!#m!j!($!!%!!!%!!!!!!!#!!5!!!!!!!$)!J!!!!!!!!!!!rrrrp`%
8$%&LEh9d)%e`B@0Vb3!!!!!&5'9XF-N!!!!!!5d!!!!!!!!!!*!!!!B!!!!!!'S
!j3"q!6-%"N4PBfpNC3!!!!!!L3$P!*`"-`3'3f&ZBf9X!!!!!!!N!18!1!%c"!T
"C'3J4QPXCA2*!!!!!!"#!18!9J%c"!C5C@e[GQ8!!!!!!"i!%3#K!-b!!!!!!!!
!(J$,!+%!fS!!!!!!!!!*!"%!'J##L""'D@aPFb"8Eb"%C@0[C'8k!!!"NJ!8!!!
!!!!3!!`!!38!!!!!!!!!!!!!!!!'!"!!$!!"!!!!!!!!!!!!!!!!!Id!%!!-!!%
&!!!!!!!!!!!!!!!##`!3!!`!!3!!!!!!!!!!!!!!!!*C!"!!$!!!!!!!!!!!!!!
!!!!!!PS!%!!-!!%!!!!!!!!!!!!!!!!'+`!3!!`!!38!!!!!!!!!!!!!!!Bj!"!
!$!!"!!!!!!!!!!!!!!!!"VF!%!!-!!!!!!!!!!!!!!!!!!!'Z!!3!!`!!3!!!!!
!!!!!!!!!!!PP!"!!$!!""3!!!!!!!!!!!!!!#AF!%!!-!!%!!!!!!!!!!!!!!!!
+"3!3!!`!!38!!!!!!!!!!!!!!!Sa!"!!$!!"!!!!!!!!!!!!!!!!#p-!%!!-!!%
&!!!!!!!!!!!!!!!,l3!3!!`!!3!!!!!!!!!!!!!!!"#2!"!!$!!""!!!!!!!!!!
!!!!!%-)!%!!-!!%!!!!!!!!!!!!!!!!61J!3!!`!!33!!!!!!!!!!!!!!"0Y!"!
!$!!"!!!!!!!!!!!!!!!!!#!!*`!"!9-"rJ!)!!!"!!!!!!!,5'9XF#"AD@jNEhF
!!!!!!!FU+LSU!!-!!!!!0'e338X!!!!"4P*&4J!$!!!!J!!"!)%!!J##!!-!JdP
$6L-!!`!!!)!!!3#"!!)!JJ!$!!!!!"E569""3dX0$8e`B@0V)'Pc)'%JF(*[Ch*
KE5"NCA0TCfjPC#"dEb"`B@0V)'&ZC#"eER"KBfXJCQPXCA-JD@jdEb"058e&)#K
0G@adDA"eFR"[Ff8J5@jdCA*ZCA3J6@&TE#"&H(4PER0TEfjc+5"cG'&ZC'&bC#"
PE'9MG(*[EQPM)'eKD@`JE@9cFf&RCA-Z)#"9FfPZCb"058e&,#"jEh8JBf&Z)(0
PEQ3JD@eKCf9c,#"KG@4TEb`JE@pdD@pZ)("TBh4eFQ9c)'&ZC#"[G'KPFL"NBA4
K)'*PG(GPC@iJC'PQCQ9bC@jd)'0[EA"eG'9bFb"fD@%JC@eKD@`Z)#"*EL"[FQ4
PFL"dEb"QB@0TE'PdBA4P)(9cC5"[CL"058e&,#"dD'Pc)("bEfGbB@dJDA-JBAC
KD@aKBQaP)'C[FL"%6e-X)%eKBfPZG'pcD#"KEQ3J98j*@#"MEfe`GA4PFR-Z)#"
'Eh)JE@pbC5"TEQC[FQeKG'P[EL"cC@jN)'9YB@PX)(4[)'TRE5Y!Bfee,Q9NG5"
[FL"MD(*TFfiV3'0YG5jPC(8Z)#"*CL"jEh8JE@&VC5"TER4PFQ9cG'PZCb"YEf4
TCQPMBA4TEfjc)(4[)%e`B@0V,#"`E'9KFf8JBfpZG'&MG#"MD(*TFfiV3'0YG5j
PC(8Z$3e&EQ0[C'PZCb"'D@aPF`d09'mJC@jMEf4P)'%JCQPXC5`JFf9XC@0d)(4
SC5$54@jMEf4P)%CTE'A*db"TG'9Y)'PZ)(4SC5"'D@aP)'ePER8X)'pb)("bCA0
c)"&&,L!J9'KTFb"hD@aX)'CTFR0d)'*bD@jR)(9`)'&Z)'p`C@iJC'PKE'pR)(4
[)'&XE'ph)(P[G5"dEb"cC@aPBh3JG'KP)'CTE'8JH@pe)(GKER3JG'mJC@jMEf4
P,L!J9fKPEL"jEh8JD'&fC5"QD@jTFfKPC#"cC@aPBh4TEQFJB5"QD@aP,#"TG#"
hD@aX)'*bD@jR)(9`)'%JC'PKE'pR)'&cDfPZCb"QEh)JG'KP)0*058e&)("KFR3
JF(*PCQPidb"dEb"cBACP)(4SC5"QD@aP)'&c,L!J5@BJG'KP)'peG("eG#"PE@&
TE#"YCA0cB@GP)'0KEL"LC5"cBACPC#"TEL"K)(0TEQGXC5"dCAKd)'CTE'8X)(4
SC5"QD@aPEQ&YC5"jEh8JFf9XC@0d)'KPFQ8JGfPXE#"LC5"eFf9N,L!J5@BJG'K
P)'peG("eG#"YGA0d)'*P)'*bEfYPEL"TER4[)(0PGQ9bB@`JC@eKD@`JE@9cFf&
RCA-X)(4SCANJGfPXE#"LC5"ZB@ePC#!mEQ&YC6iZ-$%X)$aZB@eP2Li`-L`Jb5"
hD'9bC5!mEQ&YC6iJDA-JG'KP)0*058e&)("KFR3JF(*PCQPidb"jEh8JFf9XC@0
d,L!J@@pe)'eKH5"KE(0[)'9ZG'9b)'%JFh9LDQ9MG#"QEh)JH@peFL"PE@&TE#!
SD@BJH@pe)'9ZG'9b)'j[G'KTEQFX)(4SC5"ZB@eP)'pQ)(4SC5"[FQPRD@jKE#"
QD@aP)'Pc)(9cC@3T,L!J@@pe)'eKH5"KE(0[)(0`C@0TCRNJG'KP)0*0BAKTEA9
Y)&"KFR3J8fPkCG-JEfBJG'KP)'ePFh0KCf9c,L!J9'KTFb"TFb"dD'8JER9YBQ9
b)'pQ)'0SBA*KBh4PFR-JB@aXEhGPC#"`CA)JE@9cFf&RC5iJ)%j[)'e[FQ8JG'K
KEL!f-$!`-#"cD'peE'3JBQ8JGA0PC#"dEb"`FQ9fC@jd)(P[GA)JE@9cFf&RCA-
JCf9dG'PZCb"MD'p`F'9N)'*j)(4bB@jcF'pbG#"cHA0dC@ec)(GSD@0S)'KKGQ8
JE@9cFf&RC5"XC@jRG'JJE'PYDA4c,L!J4QPZB@aXH5`JD@BJH@pe)'0SC@0V)(4
SC5$53@4N)'4PFf0bDA"dD@pZ)'CTE'A6)'*[H#`JH@pe)(GTE'`JBQ8JF(*[EA"
dC@3JCQpb)'%JG'9iG#"QD@aP)(4[)'PZBfaeC'8JC'9cBh*TBQPZCb"dD'8JCQP
XC5"jEhA9FQ8JFf9ZC'PZCbi0$84PBfpND@jR)%CTE'9c$3e8Eb"NC@0[C'8JB5"
cCA3JEfBJ68P045"[FL"eG@9ZBfpNC@3JC@aPBh4bEfjTBb"YB@PX)'CTE'9c,#"
cC@aPBh3JG'KP)0*%C@0[C'8J6@&TE#"'D@aPFmR6)'PdC@dJD@iJG'KP)%CTE'8
JE@9ZG5`JEh)JF(*PFh-J%83Z)#"CEh8JGfPXE#"LC5"`FQ9cC@jdC@3JGfPdD#"
K)(0dB@jNBA*N)'p`C@iJC'PKE'pR)(4[)(0PE'9MG#"dD'8JCQPbFh3JCQPXC5"
jEh8JGfPcD#"dEb"NC@0[C'8Z)#"2EQ0P)(P[GG9fC5"YB@4P)(P[GA)JFf9XC@0
dD@pZ)(P[G5"hD@aX)'*P)("bCA0PER4PC#"hDA4S)'%JE'PcG#"[CL"KE'`JCQP
XCA-JG'KKG#"SBACP)(4SC5"cB@eP)("bC@CTH#!SCQpXE'phC@3JBRNJB5"ZG@e
LCA)T)'&c)(4SC5"QD@aP)(P[G5"cC@aPBh4PC#iJ)&P[G5"YBANJB@4N)'pb)(*
PE@pfC5"QD@aPFb"KG#"hD@aX)#KhDA4S)(4SC5$53@4N)%CTE'9cbG-JB@jN)0*
5C@e[GQA6)'*eG(4[ER-T,#"[FL"cG'&bG#"dD'8JC'9MEf4P)("bEf0PFh-JBRN
JF(*PFh0TEQFJG'KP)0*%C@0[C'A6)'*eG(4[ELiJ)%e`B@0V)(GTE'`JF(*[Bf9
cFb"dD'8JCQPXCA-JB@jN)(0KGQ8JG'KP)'peG("eG#"TEL"dD'8JBA"`FQp`FQP
KG'8JCQPXC5"ZB@ePFbiJ)%PQ)(P[G5"bC@0PDACP)'pZE(NJF'&bG#"[CL"dD'8
JCQPXCA-JH@pe)(GTFfJJG'mJC'9MEf4P,#"0F'&MDb"hD@aX)(0dEh*P)(4PEA"
[FQ&bH5"QD@aPFb"TEL"K)0*YF'&MDbedEA$6)'C[E'4PFL"[EL"dD'8JC'9QBA9
XG#"fEfaeE@8JG@jdD@`JG'KP)(*PFh3JEfBJG'KP)'CTE'9c)(P[G5"hDA0S)(4
[)'4PBfpNC5"SBACP)'*PC@iJFQ9MC@PfC@3Z$3e@D@9hD@jR)&4PH(3J4QPXCA-
0$8&c)'&Z)'&NC'9N)'0[ERCPEQPPEQ0P,#"0F'&MDb"KE'a[Gh-JH@pe)(4[)(C
TCAFJG'9iG#"QD@aPFb"TEQ0XG@4TEQFJG'KP)'9YB@PX)'CTE'9c)'Pd)'0bC@&
dCA-X)'&c)'a[EQFJBA-JG'K[Ff8JCQPXCA-JBA*PEY9d)(4[Eb"XEfjR,Jd08f9
dG'PZCb"8HA"P,d0bC@&dEh)JEh"dD@pZFb"QEh)J68P045"[GA4`GA30$8e`B@0
V)(*PBfpREQPkCA-JdR4PH(3[F'aKD@l6,#$5D@eKCf8[CfPQdb"KEQ3JdQPYB@G
P,fT`C@I6)'CTE'9c)'&eG'pYBA4TBf&XE(NJB@jN)(0dEh*PFb"dD'9Y)(GTG'J
JGA0PCR9X)(4jF'8JB@jN)'0bC@&dEh)JCQPPE'4c,L!J5@BJH@pe)(GTFfJJG'm
JB@4N)(0eF("[FR3JCQpb)'e[FQ8X)'pb)'0SB@jRC5"dD'8JBh*PBA4[FR-JG'K
KG#"0F'&MDb"eFf9c,#"[F'9Z)(4SC5"0F'&MDb"KF("XD@0KG'P[EL"eFfPZCb"
5CA0&C'Pd,#"KEQ3JB@4N)'pb)'e[C'PQH5"dD'8JdP4j3h,6)#K8HA"P,d0bC@&
dEh)T)(*PFfpeFQ0PFb"dD'&d)%e`B@0V)(9cCA-Z)#"8D'8JFQ9cEh9bBf8JEQ&
YC5"[CL"dD'8JdP4j3h,6)(*PFfpeFQ0P)(0SEh9XC#"bC@CXC@0d)(4SC5"058e
&)(4jF'8JG'KKG#"TG#"bCA"bCA0PER4c,Jd04'PcG(*TBR9dD@pZ)'&ZC#"MEh"
jFQPRD(30$80[F(PbD@GSG##T)$%j16-J3RNJ5QpSEL"0H@9bFb"KEQ3J3fKbDA-
J6Q9hE@&Z$8&XE#"5D@GSG(-J8Q9cCA*fC@3Z$3e3CA*YDA0cD@pZ)(4[)(9cC5`
JBfp`H5`JE@pND@Cj,#"KEQ3JC'PcG(*TBR9dC5"dD'Pc)(0[CR4hBA*P)'&ZC#"
TG(-JC'pMG@ePER4KG'P[EL"QEh)JB@jj)("eFR"[Ff8JDA-JD'9bC@*j)'GbB@j
dC@3JGfPdD'peG#"QC@8X)("bEhCTC'9N)(4SBA3JG'KP)'&LEhCP)'0[F(PbD@G
SG#"ZEh4TBf8JBA"`C@&b)'PZ)'&XE#"MEh"TCA-JB@jN)(4SBA3JBQpdD#"dD'&
d)'0[F(PbD@GSG#"ZEh4TBf8JB@jN)(4SDA-JF'9bE@PcFfP[EL"ZEh4TBf8JBA"
`C@&b)'PZ)(0eF("[FR4TEQFJC'pMG@ePER4KG'P[EL`JB@jN)(4SBA3JG'KP)'j
KE@9c)'pQ)%T[D'iJ6APPFR-JB@jN)%0SFQPc)%jPGfeKEL"ZEh3JBQ8JGA0PC#"
TEL"KC(CPFR4TFfPZCb"[FL"`G@*XD@0TG(NJF'9bG'&TEQPZCb"dEb"NDA0dFQP
LGA4TEfiJEfBJG'KP)(0[CR4hBA*P)(GTG'K[GA3JFh"PBfPQD@-X)(GbDA4dC@i
JF(*TEh)JF'9bE@PcFfP[ELiJ)%T[D'iJ6APPFR-JB@jN)%0SFQPc)%jPGfeKEL"
YB@YP)'j[)(*PF(*PFf9ZG'&dD@pZFb"KBQpeG#"dD'8JFh9TG'&LD@aTG(NJEfB
JG'KTFb"cEfCdGf&bC5"QEh)JB@jj)("eFR"[Ff8Z)#"*G#"TFb"`FQpfD@4PC#!
LBA-JDA-L)(GTG'K[GA3JCAK`FQ9cFb"[FL"TEA"XD@9N)(GKFR*KER4j,Jd05Np
)6L"0@8958b""6N3J3dK559-J6N9A68&1)%4*8d0-38P0)%&-6#"A39*538j8589
6)&G*9%JJ8N9(39*%)&42)&4)59-J8dp'9&G"8N8X)%P13da94%P14b""6%`J58e
36%P&4#"A39*538j85896)%p')%e&8N0)38j838**6%P8@5""6N3J4NP86N968b`
J58iJ6NmJ49C&6P3J8dK"6%`J5Np)6L"0@8958b"28L"$5&**8b"149G038iJ3N8
J6%P"3Na&)%C28L""6PNJ8e"&3dP"6#`J58j%59*&3e3J6e)J3dp18d9498919%P
"6#"%38e"4d96)%p5)%&1@5"%38e"4d96)&G)39466d9@49)J8N9698a858j()%C
56ddJ6%p68b"24L"98d8X)%4"9%%J6e)J8&*24NP88b`J9dK&9%K&8L"*6L""6L"
"3e4*6diJ6dBJ3dp19&*"3e3X)%j&4da*4d913d8J6e)J6e4)49)J9%p59%P299-
J380858p1,#""8NP658j()%p99#"24L"28L"*6L"$6dj1480858p1)&G*9%JJ9%K
&)&9645"28L"349*'6e*038j$45"24L"85%P6)&024P4A39*&,Jd08'pbG'P[ER-
JEfBJG'KTFb"MEf4P)'KKGQ8JG'KP)'C[E'a[GfPZCb"MEh"jFQPRD(3k$3e$Eh"
jFQPRD(3JU5!a16Na)%*PE'`J3fpYEA9ZD@0KG'P[ER-J8Q9cC@&bBfJX)%PZBbi
J+%*PE'aMEh*P+3d08'9bE@PcFfP[EL"dEb"eFf8X)'0[F(NX)'e[C'PQH5`JB@j
N)'4TFh4bD@*eG'8JG'KTFb"YBA4PFQPKE#"QEh)JB@jj)("eFR"[Ff8JB@jN)(G
TG'K[GA3JCQ9P)'Pc)'KPFQ9LH5"RFQ&ZG'9N,#"`FQpfD@4PC#"dD'&d)(4SC5"
KBQpfC5"MEh"jFQPRD(3JEQpdD@0P)'&ZC#"dD'Pc)("PFQeTFh0TEfiJEQpdD@0
P)!eKF("PBA)JD@iJB@aX)'0[F'PPFb`JB@jN)(4SBA3JG'KP)'jKE@8JEfBJ3Q9
XE'0[FQ8JEQpd)'*P)(9cC@3JD@iJB@4fCA*dDA0TEQFJEh)JF(9LE'PMDA4j)("
PFR4KD@jTEQFJG'mJG'KTFb"YBA4PFQPKE#"hDA4SEh9d)(4SC5"cF'9MD@CTBb`
JF(*TEh)JGh*TG(4PEL"`CA*YDA0cD@pZ)'pQ)'&Z)'&eG'K[FQPkC@3JFQ9`FQ9
cC@jdBA4TGQ8JEfBJ3Q9XE'0[FQ8Z)#"#48a-3dp545"038Y&8b"16b"549"5490
&6P4"9%P26P-J38*2993J9%K&)%&$3e95380C)%p5)&09594"3NP-594C)%p')&4
)59-J68&849**38`J4Np5)%&1@5"399*36e0&,L!J593J59-J8&*29NP%483J)N&
6)%P6)L`J9dP85%p99#""6PNJ49K38N968b"28L"*69"-589%)&G"8P*"6P4*49-
Z$3e3Eh*dD@pZFb"[CL"dD'Pc)'0[C'8JD'&fC5"dD'8JCQpXE'phD@jR)'0[F(P
bD@GSG$S0$80[F(PbD@GSG##T)$%j16%Y-L`J8P0")%4KG'%J8f9MGA*TG(NX)%P
ZBbiJ3h*PBA4PC#!a16Na,L""E'`JFQPRD(4c)(*PFf9bGQ9N,Jd06'PMC@jcC5"
dEb"MEh"j)'&ZC#"eFf8JG'KTFb"cEfCdGf&bC5"TFb"RFQ&ZG'9N)("bEhCTC'9
N)(4SBA3JDA3JDA-JD@4PER4TCQPPC#"KFb"dD'8J)P*635"%BA4K)&0PBh9bDA4
j,#"*EQ-Z)%e%05"0CA0cB@GP,84TCf9cG#""E'G[FQPdD'dL)'PZ)'&XE#"YBA4
PFQPKE#"YC@jdD@pZD@jR)'pb)(*PCQ9bC@jMD@jR)(4SDA-JFfpQG(GKFQ8JEh)
JG'KTFb"QG@jMG'P[ELi0$8aTBf9ZFf8JDA-JB@acEb"RFQ&ZG'9N)(4[)'eKDf8
JB@jN)(9cC5"NCA*TGQ&dDACP)(G[FQYc)("bEhCTC'9N)(4SBA3JFh9MD#"hEh*
VFb"KFQ8JD@4PER4TCQPPC#"KFb!LC'9bDACPC#"QFQpY)(4SC5"58d%J4'&dB5"
6C@0eFQPdH5`J5@jM,L"04$8J6@9cFf&RC5e%D@GPFh3J3@aREh*TG'KY)L"TEL"
KE'`JE@&dCA*TB@`JE@9ZG'P[EQPZCb"[FL"bC@CPFQ9ZBfPZCb"dD'8JC'9bDAC
PC#"hEh*V,Jd08P0")%4KG'%J8f9MGA*TG(NX)%PZBbiJE@&VCA-JEQmJFQ9`FQ9
cC@jdBA4TEfjc)'0[EQ0PFQjTEQFJC@PdD'9b)(4SC5"YCA*MD'&ZG'&LD@aTG(N
JEfBJG'KTFb"cEfCdGf&bC5"[FL"dD'8JFh9TG'&LD@aTG(NJEfBJG'KTFb"cEfC
dGf&bC5"QEh)JB@jj)("KFR4TBh9XBA)JF(9bF'pcC5iJ5A3JDA-JF(*[GQPNC@3
J)Q&c)'Pc)L"hDA4SEh9d)'9iF(*PFh-JEh)JD@e`E'PPC#"hBA*bB@jdH5"[CL"
KERNJDfPZC#i0$94SCA0P)'j[G'PMCA-JEA9cG#"LC5"bCA4KD@jPC#"TEL"KERN
JBfp`D@9c)'pQ)'&ZH5"`BA*d)'pQ)(4SDA-JC'pMG@ePER4KG'P[EL"KEQ3[Eh)
JFfpQG(GKFQ8Z$3!!!"F"!)!!!!!%9M%Z-!Y@CA*cD@pZ)$%Z-!!!!-)!"3!!!!!
!!!!!!*J"P!J!!!!!!!!)!+S!'`$L#!90F'&MD`!!!!!!!&`!@!"a!63)(NeKBfP
ZG'pcD#"`Eh*d)'*j)%0SFQPc)%jPGfeKEJ!!!!!!(`#C!$)!m`J+9Q9bFfP[EL"
H-!!!!!!!43#6!&J!qJJ0BRNJ5QpSEL"0H@9bF`!!!!!!!(8!'J#)!A))-&0PC5"
)C@a`b5"QEh)J3fp`HA*TCfKd)'&ZC#"%DA0dFQPLGA4TEfiJ6@9cFf&RC3!!!"J
A-5i`)+NJ-6Nj-b"LH5"+4ddJ*L"$5Ni!!!%!!!!M[!!!)V`!!!-X!%(Dj!X'!!!
!(!*Q!!p%594-!!8!JN4-6dF!!J$+689193!#!1j03N&5!!!"%PG*6N3!!J%H4P*
&4J!$!8**3diM!!)"FQPMFb-!!J'@3Nj%6!!!!ETY8%&,!!!"aN&-8P3!!J(59%e
36!!!!IC8H80b!!)#!P4&@&3!!!)QFh4jE!!!!M*fCA*c!!!#2J#!!!!J!#(D!!!
!!!#"!%dJ!!KB!!!!!!#$!%-J!!0F!!!!!!##!'FJ!!9K!!!!!!#%!(-J!!G#!!!
!!!#&!*)J!!Eb!!!!!!#!!!BJ!!J'!%(AF!#"!&3J!!-F!%(Ci!##!&XJ!!9&!%(
Ck!#"!"!%!!Cr!!!!!!##!"8%!!!!!!!!!!#!!"S%!!JL!!!!!!#!rrm%!!"d!!!
!!!#!!)-J!!#!!!!!!!2S!#!J!!#D!!!!!!#"!-%J!!U#!!!!!!#!rrm!!!#k!%(
BP!#"rrm!!!)0!%(BM!##rrm!!!1Z!%(BK!#$rrm!!!UQ!%(BI!#!rrm!!!)B!%(
BN!!!JIrr!!!"#3""f)J!J[rr!!!$Z3""f)!!J2rr!!!!a3""f$3!J[rr!!!%[3"
"f$J!JIrr!!!&!3""f%3!J2rr!!!+X3""fFJ!!!!U!!!LS!""f(J!J`!j)!!$5J!
!!!!!K!"l)!!(iJ!!!!!!K3#))!!(p!!!!!!$k3#F)!!(a!!!!!!!J!#K)!!(S!"
"f(3!J3#X)!!(V!""fD`!JJ#f)!!(Z!""`b!!J2rr)!!+k3""fBJ!J2rr)!!)l!!
!!!!!J2rr!!!K[`""fG3&B@*[GA3*3@*[GA3J3Qpi"%CTE'8%4@4TG!9"F("XC3P
ME'P`BQpKFQ316hGZCA)JFQ9cEh9bBf8*9f&bEL""E(*d#9GKFQiJ3@abG!CNC@0
[C'8'C'9MEf4P#f9ZBfpNC5"cBACP#f9ZBfpNC5"cBACP"h*PF'aKBf8(FQ9`E'&
MC34dCAKd#90dEh!J3@abG!P6G'p`)%&XFR3%9(P$FJTdCAKd,h"XB@PZ#@PYB@G
P,fGTCJTTE@&RC5pUF'9R"'KPE(!Ef!:
END_OF_FILE
fi
if test -f 'mpack-1.0/mpack.mak' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/mpack.mak'\"
else
echo shar: Extracting \"'mpack-1.0/mpack.mak'\" \(392 bytes\)
cat >'mpack-1.0/mpack.mak' <<'END_OF_FILE'
PACKOBJS = dospk.obj encode.obj codes.obj magic.obj dosos.obj string.obj \
xmalloc.obj md5c.obj getopt.obj
UNPACKOBJS = dosunpk.obj decode.obj uudecode.obj codes.obj dosos.obj \
string.obj xmalloc.obj md5c.obj getopt.obj

all: mpack.exe munpack.exe

mpack.exe: $(PACKOBJS)
$(CC) $(CFLAGS) -empack.exe $(PACKOBJS)

munpack.exe: $(UNPACKOBJS)
$(CC) $(CFLAGS) -emunpack.exe $(UNPACKOBJS)

END_OF_FILE
fi
echo 'End of part 3 (of 6).'
echo 03 >> _shar_private

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:35:57 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 61
Archive-name: mpack-1.0/04

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:

# "End of part 4 (of 6)."


# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'

if test -f 'mpack-1.0/macmpack.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macmpack.c'\"
else
echo shar: Extracting \"'mpack-1.0/macmpack.c'\" \(16083 bytes\)
cat >'mpack-1.0/macmpack.c' <<'END_OF_FILE'
/* mac_mpack.c -- Mac user interface to mpack routines
*
* (C) Copyright 1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "macnapp.h"
#include "macmpack.h"
#include "version.h"

/* save watch cursor */
Cursor watch;

/* flag for active help window */
static WindowPtr helpw = NULL;

typedef struct filelist {
int vRefNum;
PCstr fname[65];
} filelist;

typedef struct listwin {
na_win win;
int count;
filelist **hflist;
ListHandle l;
} listwin;

void warn(char *str);
static void do_decodefiles(listwin *);
static void addfile(listwin *, SFReply *);
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 textinit(na_win *,long *);
static void do_decode(void);
static void do_encode(SFReply *);
static short mainmenu(struct na_win*, WORD, WORD);

#define dwin ((listwin *) win)

SFTypeList textList = { 'TEXT', 0, 0, 0 };

/* 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);
}

/* process the files in the file list
*/
static void do_decodefiles(dw)
listwin *dw;
{
int count = dw->count;
filelist *fl;
FILE *dfile;
extern long _ftype, _fcreator;

_ftype = 'TEXT';
_fcreator = 'mPAK';
SetCursor(&watch);
MoveHHi((Handle) dw->hflist);
HLock((Handle) dw->hflist);
fl = *dw->hflist;
while (count--) {
SetVol(NULL, fl->vRefNum);
if (dfile = fopen(C(fl->fname), "r")) {
handleMessage(dfile, "text/plain", 0);
fclose(dfile);
}
++fl;
}
HUnlock((Handle) dw->hflist);
SetCursor(&arrow);
}

/* 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, char *fname)
{
long size = GetHandleSize((Handle) dw->hflist) / sizeof (filelist);
filelist *fl;
char *bp;
Cell c;
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 + dw->count;
fl->vRefNum = vRefNum;
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, reply)
listwin *dw;
SFReply *reply;
{
CInfoPBRec cipbr;
HFileInfo *fpb = (HFileInfo *)&cipbr;
PCstr fbuf[42];
short idx, foundone = 0, wrefnum;
long dirid, procid;

/* find directory where file is */
procid = 0;
GetWDInfo(reply->vRefNum, &wrefnum, &dirid, &procid);

/* loop through directory */
idx = 1;
for (;;) {
fpb->ioVRefNum = wrefnum;
fpb->ioNamePtr = P(fbuf);
fpb->ioDirID = dirid;
fpb->ioFDirIndex = idx;
if (PBGetCatInfo(&cipbr, FALSE)) break;
SetClen(fbuf);

if (!(fpb->ioFlAttrib & 16) && fprefixMatch((char *)reply->fName, fbuf)) {
addit(dw, reply->vRefNum, (char *) P(fbuf));
foundone = 1;
}
++idx;
}
if (!foundone) {
addit(dw, reply->vRefNum, (char *) reply->fName);
}
}

/* 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);
DisposHandle((Handle) dwin->hflist);

return (NA_CLOSED);
}

/* 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);
}
}

/* control procedure
*/
static short listctrl(na_win *win, Point p, short item, short mods, ControlHandle ctrlh)
{
SFReply reply;
Point where;

switch (item) {
case iAdd:
where.h = where.v = 0;
SFGetFile(where, NULL, NULL, 1, textList, NULL, &reply);
if (reply.good) {
if (!dwin->count) {
NAhiliteDItem((DialogPtr)win->pwin, iOk, 0);
}
addfile(dwin, &reply);
}
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:
do_decodefiles(dwin);
case iCancel:
return (NA_REQCLOSE);
}

return (NA_NOTPROCESSED);
}

/* update the list window
*/
static short listupdate(na_win *win, Boolean resize)
{
Rect r;
Handle hand;
short type;

GetDItem((DialogPtr)win->pwin, iFileList, &type, &hand, &r);
FrameRect(&r);
UpdtDialog(win->pwin, win->pwin->visRgn);
LUpdate(win->pwin->visRgn, dwin->l);

return (NA_NOTPROCESSED);
}

/* initialize the list window
*/
static short listinit(win, data)
na_win *win;
long *data;
{
SFReply *reply = (SFReply *) 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, reply);
win->closep = listclose;
win->updatep = listupdate;
win->ctrlp = listctrl;
win->mousep = listmouse;
NAhiliteDItem((DialogPtr)win->pwin, iRemove, 255);
ShowWindow(win->pwin);
DrawDialog(win->pwin);
LDoDraw(TRUE, dwin->l);

return (NA_NOTPROCESSED);
}

/* Decode procedure: first get a file, then open decode window
*/
static void do_decode()
{
SFReply reply;
Point where;

where.h = where.v = 0;
SFGetFile(where, NULL, NULL, 1, textList, NULL, &reply);
if (reply.good) {
NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_RECENTER | NA_DEFBUTTON |
NA_HASCONTROLS | NA_CLOSEBOX, NULL, decodeDLOG, (long *) &reply,
sizeof (listwin), listinit);
}
}

/* a filter proc which handles Return, Enter, Esc, command-period properly
*/
pascal Boolean mySaveFilterProc(dialog, pevent, item)
DialogPtr dialog;
EventRecord *pevent;
short *item;
{
int c;

if (pevent->what == autoKey || pevent->what == keyDown) {
switch (c = (pevent->message & charCodeMask)) {
case '\r':
case '\n':
case 0x03:
*item = 1;
goto HILITE;

case '.':
if (!(pevent->modifiers & cmdKey)) break;
case '\033':
*item = 2;
HILITE:
NAflashButton(dialog, *item);
return (true);
default:
if (((DialogPeek)dialog)->editField + 1 == iMaximum
&& isprint(c) && c != '\t' && !isdigit(c)) {
pevent->what = nullEvent;
}
break;

}
}

return (false);
}

static long save_max;
static PCstr save_subject[257];
static short save_dflag;

/* custom file dialog procedure
*/
pascal short mySaveDialog(short item, DialogPtr theDialog)
{
Handle etext;
PCstr tstr[257];
ControlHandle ctrl;

if (item == iDescfile) {
NAgetDHandle(theDialog, iDescfile, &ctrl);
SetCtlValue(ctrl, !GetCtlValue(ctrl));
} else if (item == iOk) {
NAgetIText(theDialog, iSubject, save_subject);
NAgetIText(theDialog, iMaximum, tstr);
save_max = atol(C(tstr));
NAgetDHandle(theDialog, iDescfile, &ctrl);
save_dflag = GetCtlValue(ctrl);
}

return (item);
}

/* Decode procedure: first get a file, then open decode window
*/
static void do_encode(SFReply *reply)
{
SFReply infile, outfile, descfile;
Point where;
PCstr fname[34], mtype[257];
struct lookupct *ctptr;
char *scan;
short mapcount, i;
Handle h;
ResType type = 'TyCr';
extern long _ftype, _fcreator;

where.h = where.v = 0;
if (!reply) {
SFGetFile(where, NULL, NULL, -1, NULL, NULL, &infile);
if (!infile.good) return;
} else {
infile = *reply;
}
PtoPCstrcpy(fname, (char *) infile.fName);
if (scan = strrchr(C(fname), '.')) {
*scan = '\0';
SetPlen(fname);
}
if (PCstrlen(fname) >= 25) {
*fname = 25;
SetClen(fname);
}
PtoCstr(infile.fName);
RETRYSFP:
SFPPutFile(where, "\pMIME part prefix:", P(fname),
mySaveDialog, &outfile, encodeDLOG, mySaveFilterProc);
if (outfile.good) {
PtoCstr(outfile.fName);
if (!strcmp((char *)infile.fName, (char *)outfile.fName)) {
yell("The output filename must be different from the input filename");
goto RETRYSFP;
}
if (save_dflag) {
SFGetFile(where, NULL, NULL, 1, textList, NULL, &descfile);
if (!descfile.good) {
save_dflag = 0;
} else {
PtoCstr(descfile.fName);
}
}
mapcount = CountResources(type);
*mtype = '\0';
for (i = 1; i <= mapcount; ++i) {
h = GetIndResource(type, i);
if (h && **(OSType **)h == infile.fType) {
GetResInfo(h, &i, &type, P(mtype));
if (ResError() == noErr) break;
}
}
SetClen(mtype);

_ftype = 'TEXT';
_fcreator = 'mPAK';
SetCursor(&watch);
encode(infile.fName, save_dflag ? descfile.fName : 0,
*C(save_subject) ? save_subject : infile.fName, NULL, save_max,
PCstrlen(mtype) ? C(mtype) : NULL, outfile.fName);
SetCursor(&arrow);
}
}

/* open a textedit window & load a file into it
*/
static short textinit(na_win *win, long *data)
{
Handle h = (Handle) data;
long size;

TextFont(monaco);
TextSize(9);
size = GetHandleSize(h);
MoveHHi(h);
HLock(h);
NATEinit(win, NATE_READONLY, 489, *h, size);
HUnlock(h);
ShowWindow(win->pwin);

return (NA_NOTPROCESSED);
}

/* Open a window for a text file
*/
static short textopen(short message, AppFile *afile, FSSpec *fspec)
{
SFReply reply;
Point where;
Handle data;
long len, saved;
short fref;
OSErr err;
Rect *sr;
FInfo finfo;
PCstr fname[257];
char emsg[512];

if (message != appOpen) return (-1);

/* find & open file */
if (!afile && !fspec) {
where.h = where.v = 0;
SFGetFile(where, NULL, NULL, 1, textList, NULL, &reply);
if (!reply.good) return (-1);
PtoPCstrcpy(fname, (char *) reply.fName);
err = FSOpen(reply.fName, reply.vRefNum, &fref);
} else if (afile) {
PtoPCstrcpy(fname, (char *) afile->fName);
if (afile->fType != 'TEXT') {
BlockMove(afile->fName, reply.fName, sizeof (reply.fName));
reply.fType = afile->fType;
do_encode(&reply);
return (0);
}
err = FSOpen(afile->fName, afile->vRefNum, &fref);
} else {
PtoPCstrcpy(fname, (char *) fspec->name);
if (FSpGetFInfo(fspec, &finfo) == noErr && finfo.fdType != 'TEXT') {
BlockMove(fspec->name, reply.fName, sizeof (reply.fName));
reply.fType = finfo.fdType;
do_encode(&reply);
return (0);
}
err = FSpOpenDF(fspec, fsRdPerm, &fref);
}

/* read file */
if (err != noErr) {
sprintf(emsg, "Could not open file %s\rError %d", C(fname), err);
yell(emsg);
return (-1);
}
if (GetEOF(fref, &len) < 0 || len >= 32000 || !(data = NewHandle(len))) {
FSClose(fref);
sprintf(emsg, "File %s is too long to view.", C(fname));
yell(emsg);
return (-1);
}
MoveHHi(data);
HLock(data);
saved = len;
err = FSRead(fref, &saved, *data);
HUnlock(data);
FSClose(fref);
if (err != noErr || saved != len) {
sprintf(emsg, "Could not read file %s\rError %d", C(fname), err);
yell(emsg);
return (-1);
}

/* open NATE window */
sr = NAscreenrect(NA_TOPSCN | NA_RIGHTSCN | NA_TITLEOFFSET | NA_STACK);
if (sr->right - sr->left > 512) sr->right = sr->left + 512;
NAwindow(sr, NA_USERESOURCE | NA_FORCESIZE | NATEflags, C(fname), textWIND,
(long *) data, sizeof (nate_win), textinit);
DisposHandle(data);

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);
}

/* Main menu procedure
*/
static short mainmenu(na_win *win, WORD menuid, WORD itemno)
{
short status;
MenuHandle mh;
PCstr version[32];

switch (menuid) {
case mApple:
if (itemno == iAbout) {
CtoPCstrcpy(version, MPACK_VERSION);
ParamText(P(version), NULL, NULL, NULL);
return (NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_RECENTER
| NA_DIALOGUPDATE | NA_MODAL, "About", aboutDLOG, (long *) NULL, 0, NAabout));
}
if (!helpw) {
NAwindow(0, NA_USERESOURCE | NATEflags | NA_SMARTSIZE, NULL, helpWIND,
(long *) NULL, sizeof (nate_win), helpwindow);
} else {
SelectWindow(helpw);
}
break;

case mFile:
switch (itemno) {
case iEncode:
do_encode(NULL);
return (NA_PROCESSED);

case iDecode:
do_decode();
return (NA_PROCESSED);

case iOpen:
textopen(appOpen, NULL, NULL);
return (NA_PROCESSED);

case iClose:
return (NA_NOTPROCESSED);

case iQuit:
return (NA_REQCLOSEALL);
}
break;

case mEdit:
switch (itemno) {
case iClipboard:
NAclipboardMenu(menuid, itemno, 'TEXT');
return (NA_PROCESSED);
}
break;
}
return (NA_NOTPROCESSED);
}


main()
{
CursHandle cursH;

if (NAinit(128, 3, textopen, mainmenu, 2, 0, iClose) == 0) {
cursH = GetCursor(watchCursor);
watch = **cursH;
NAmainloop();
}
}
END_OF_FILE
fi
if test -f 'mpack-1.0/README' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/README'\"
else
echo shar: Extracting \"'mpack-1.0/README'\" \(8012 bytes\)
cat >'mpack-1.0/README' <<'END_OF_FILE'
mpack/munpack version 1.0

Mpack and munpack are utilities for encoding and decoding
(respectively) binary files in MIME (Multipurpose Internet Mail
Extensions) format mail messages. For compabibility with older forms
of transferring binary files, the munpack program can also decode
messages in split-uuencoded format.

Versions are included for unix, pc, and mac systems.

This MIME implementation is intended to be as simple and portable as
possible. For a slightly more sophisticated MIME implementation, see
the program MetaMail, available via anonymous FTP to
thumper.bellcore.com, in directory pub/nsb


Compilation:

[unix version]

If compiling on SCO Unix or an ancient BSD without the strchr()
function, edit the Makefile and uncomment the relevant lines.

Compile with the "make" command. Install with
"make install DESTDIR=/installation/path". The default value of
DESTDIR is "/usr/local", which installs the programs in /usr/local/bin
and the man pages in /usr/local/man/man1.

[pc version]

The pc sources have been compiled with Turbo C version 3.0, though
other compilers should also work. To compile with Turbo C, use the
DOS command "make -f mpack.mak".


[mac version]

Mpack was compiled with THINK C 6.0 with the 4-byte int option turned
on (and the ANSI-small library compiled with the 4-byte int option)
and prototype enforcement turned off. Included with this distribution
should be the files "macproj.hqx" which is a BinHex4 version of the
THINK C 6.0 project file, and "macrsrc.hqx" which is a BinHex4 version
of the resources file.

If you wish to compile this with a different version of the THINK C
compiler, you must turn on 4-byte ints when compiling the ANSI library
and the source code. If you wish to use MPW or some other compiler
you will probably have to add additional #include statements for the
appropriate Macintosh interface headers.


Using the mac version:

See the "Help..." menu item in the application.


Using mpack: [unix and pc versions]

Mpack is used to encode a file in one or more MIME format messages.
The program is invoked with:

mpack [options] -o outputfile file

Where "[options]" is one or more optional switches described below.
"file" is the name of the file to encode and "-o outputfile" is
described below.

The unix version may also be invoked with either:

mpack [options] file address...

or

mpack [options] -n newsgroups file

Where "address..." is one or more e-mail address to mail the resulting
messages to and "newsgroups" is a comma-separated list of newsgroups
to post the resulting messages to.

The possible options are:

-s subject
Set the Subject header field to Subject. By default,
mpack will prompt for the contents of the subject
header.

-d descriptionfile
Include the contents of the file descriptionfile in an
introductory section at the beginning of the first
generated message.

-m maxsize
Split the message (if necessary) into partial messages,
each not exceeding maxsize characters. The default
limit is the value of the SPLITSIZE environment
variable, or 60000 characters if the environment variable
does not exist. Specifying a maxsize of 0 means there
is no limit to the size of the generated message.

-c content-type
Label the included file as being of MIME type
content-type, which must be a subtype of application,
audio, image, or video. If this switch is not given,
mpack examines the file to determine its type.

-o outputfile
Write the generated message to the file outputfile. If
the message has to be split, the partial messages will
instead be written to the files outputfile.01,
outputfile.02, etc.


The environment variables which control mpack's behavior are:

SPLITSIZE
Default value of the -m switch. Default "60000".

TMPDIR [unix version only]
Directory to store temporary files. Default "/tmp".

HOSTNAME [pc version only]
Domain to use in generated message-ids. Default "random-pc".


Using munpack:

Mpack is used to decode one or more messages in MIME or
split-uuencoded format and extract the embedded files. The program is
invoked with:

munpack [options] filename...

which reads the messages in the files "filename...". The pc version
does accept wildcards. Munpack may also be invoked with just:

munpack [options]

which reads a message from the standard input.

If the message suggests a file name to use for the imbedded part, that
name is cleaned of potential problem characters and used for the
output file. If the suggested filename includes subdirectories, they
will be created as necessary. If the message does not suggest a file
name, the names "part01", "part02", etc are used in sequence.

If the imbedded part was preceded with textual information, that


information is also written to a file. The file is named the same as
the imbedded part, with any filename extension replaced with ".desc"

on the unix version or with ".dsc" on the pc version.

The possible options are:

-f
Forces the overwriting of existing files. If a message


suggests a file name of an existing file, the file will be

overwritten. Without this flag, the unix version appends
".1", ".2", etc to find a nonexistent file. Without this
flag, the pc version replaces any filename extension with


".1", ".2", etc to find a nonexistent file.

-C directory
Change the current directory to "directory" before reading
any files. This is useful when invoking munpack


from a mail or news reader.

The environment variables which control munpack's behavior are:

TMPDIR [unix version]
Root of directory to store partial messages awaiting
reassembly. Default is "/tmp". Partial messages are
stored in subdirectories of $TMPDIR/message-parts-$USER/

TMP [pc version]
Root of directory to store partial messages awaiting
reassembly. Default is "\tmp". Partial messages are
stored in subdirectories of $TMP/parts/


Acknowledgements:

Written by John G. Myers, jg...@cmu.edu
The mac version was written by Christopher J. Newman, chr...@cmu.edu


Reporting bugs:

Bugs and comments should be reported to jg...@cmu.edu. Please include
the version number and the platform in the report.


Legalese:

(C) Copyright 1993 by John G. Myers and Christopher J. Newman
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 John G. Myers or
Christopher J. Newman not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission. John G. Myers and Christopher J. Newman make no


representations about the suitability of this software for any

purpose. It is provided "as is" without express or implied warranty.

JOHN G. MYERS AND CHRISTOPHER J. NEWMAN DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL JOHN G. MYERS OR


CHRISTOPHER J. NEWMAN 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.


Portions of this software are derived from code written by Bell
Communications Research, Inc. (Bellcore) and by RSA Data Security,
Inc. and bear similar copyrights and disclaimers of warranty.

END_OF_FILE
fi
if test -f 'mpack-1.0/codes.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/codes.c'\"
else
echo shar: Extracting \"'mpack-1.0/codes.c'\" \(10382 bytes\)
cat >'mpack-1.0/codes.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers

* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the

* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*


* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND

* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)

Permission to use, copy, modify, and distribute this material
for any purpose and without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies, and that the name of Bellcore not be
used in advertising or publicity pertaining to this
material without the specific, prior written permission
of an authorized representative of Bellcore. BELLCORE
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.


*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "xmalloc.h"

#include "md5.h"

static char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static char index_64[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
};

#define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])

static char index_hex[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};

#define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)])

to64(infile, outfile, limit)
FILE *infile, *outfile;
long limit;
{
int c1, c2, c3, ct=0;

if (limit && limit < 73) return;

while ((c1 = getc(infile)) != EOF) {
c2 = getc(infile);
if (c2 == EOF) {
output64chunk(c1, 0, 0, 2, outfile);
} else {
c3 = getc(infile);
if (c3 == EOF) {
output64chunk(c1, c2, 0, 1, outfile);
} else {
output64chunk(c1, c2, c3, 0, outfile);
}
}
ct += 4;
if (ct > 71) {
putc('\n', outfile);
if (limit) {
limit -= ct + 1;
if (limit < 73) return;
}
ct = 0;
}
}
if (ct) putc('\n', outfile);
}

output64chunk(c1, c2, c3, pads, outfile)
FILE *outfile;
{
putc(basis_64[c1>>2], outfile);
putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
if (pads == 2) {
putc('=', outfile);
putc('=', outfile);
} else if (pads) {
putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
putc('=', outfile);
} else {
putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
putc(basis_64[c3 & 0x3F], outfile);
}
}

PendingBoundary(s, Boundaries, BoundaryCt)
char *s;
char **Boundaries;
int *BoundaryCt;
{
int i, len;

if (s[0] != '-' || s[1] != '-') return(0);
s+=2;

for (i=0; i < *BoundaryCt; ++i) {
len = strlen(Boundaries[i]);
if (!strncmp(s, Boundaries[i], len)) {
if (s[len] == '-' && s[len+1] == '-') *BoundaryCt = i;
return(1);
}
}
return(0);
}

static char *md5contextTo64(context)
MD5_CTX *context;
{
unsigned char digest[18];
char encodedDigest[25];
int i;
char *p;

MD5Final(digest, context);
digest[sizeof(digest)-1] = digest[sizeof(digest)-2] = 0;

p = encodedDigest;
for (i=0; i < sizeof(digest); i+=3) {
*p++ = basis_64[digest[i]>>2];
*p++ = basis_64[((digest[i] & 0x3)<<4) | ((digest[i+1] & 0xF0)>>4)];
*p++ = basis_64[((digest[i+1] & 0xF)<<2) | ((digest[i+2] & 0xC0)>>6)];
*p++ = basis_64[digest[i+2] & 0x3F];
}
*p-- = '\0';
*p-- = '=';
*p-- = '=';
return strsave(encodedDigest);
}


from64(infile, outfile, digestp, boundaries, boundaryct)
FILE *infile, *outfile;
char **digestp;
char **boundaries;
int *boundaryct;
{
int c1, c2, c3, c4;
int newline = 1, DataDone = 0;
char buf[3];
MD5_CTX context;

if (digestp) MD5Init(&context);
while ((c1 = getc(infile)) != EOF) {
if (isspace(c1)) {
if (c1 == '\n') {
newline = 1;
} else {
newline = 0;
}
continue;
}
if (newline && boundaries && c1 == '-') {
char Buf[200], erora;
/* a dash is NOT base 64, so all bets are off if NOT a boundary */
ungetc(c1, infile);
fgets(Buf, sizeof(Buf), infile);
if (boundaries
&& (Buf[0] == '-')
&& (Buf[1] == '-')
&& PendingBoundary(Buf, boundaries, boundaryct)) {
break;
}
warn("Ignoring unrecognized boundary line");
continue;
}
if (DataDone) continue;
newline = 0;
do {
c2 = getc(infile);
} while (c2 != EOF && isspace(c2));
do {
c3 = getc(infile);
} while (c3 != EOF && isspace(c3));
do {
c4 = getc(infile);
} while (c4 != EOF && isspace(c4));
if (c2 == EOF || c3 == EOF || c4 == EOF) {
warn("Premature EOF");
break;
}
if (c1 == '=' || c2 == '=') {
DataDone=1;
continue;
}
c1 = char64(c1);
c2 = char64(c2);
buf[0] = ((c1<<2) | ((c2&0x30)>>4));
putc(buf[0], outfile);
if (c3 == '=') {
if (digestp) MD5Update(&context, buf, 1);
DataDone = 1;
} else {
c3 = char64(c3);
buf[1] = (((c2&0XF) << 4) | ((c3&0x3C) >> 2));
putc(buf[1], outfile);
if (c4 == '=') {
if (digestp) MD5Update(&context, buf, 2);
DataDone = 1;
} else {
c4 = char64(c4);
buf[2] = (((c3&0x03) <<6) | c4);
putc(buf[2], outfile);
if (digestp) MD5Update(&context, buf, 3);
}
}
}
if (digestp) *digestp = md5contextTo64(&context);
}

fromqp(infile, outfile, digestp, boundaries, boundaryct)
FILE *infile, *outfile;
char **digestp;
char **boundaries;
int *boundaryct;
{
int c1, c2, sawnewline = 1, neednewline = 0;
/* The neednewline hack is necessary because the newline leading into
a multipart boundary is part of the boundary, not the data */
MD5_CTX context;
char Buf[200], *s;
char c;

if (digestp) MD5Init(&context);

while (fgets(Buf, sizeof(Buf), infile)) {
if (sawnewline && boundaries
&& (Buf[0] == '-')
&& (Buf[1] == '-')
&& PendingBoundary(Buf, boundaries, boundaryct)) {
neednewline = 0;
break;
}
/* Not a boundary, now we must treat THIS line as q-p, sigh */
if (neednewline) {
putc('\n', outfile);
neednewline = 0;
if (digestp) MD5Update(&context, "\r\n", 2);
}
for (s=Buf; *s; ++s) {
if (*s == '=') {
if (!*++s) break;
if (*s == '\n') {
/* ignore it */
sawnewline = 1;
} else {
c1 = hexchar(*s);
if (!*++s) break;
c2 = hexchar(*s);
c = c1<<4 | c2;
putc(c, outfile);
if (digestp) MD5Update(&context, &c, 1);
}
} else {
if (*s == '\n') {
sawnewline = 1;
neednewline = 1;
}
else {
putc(*s, outfile);
if (digestp) MD5Update(&context, s, 1);
}
}
}
}
if (neednewline) {
putc('\n', outfile);
neednewline = 0;
if (digestp) MD5Update(&context, "\r\n", 2);
}
if (digestp) *digestp=md5contextTo64(&context);
}

fromnone(infile, outfile, digestp, boundaries, boundaryct)
FILE *infile, *outfile;
char **digestp;
char **boundaries;
int *boundaryct;
{
char buf[1024], *p;
int startofline = 1, neednewline = 0;
MD5_CTX context;

if (digestp) MD5Init(&context);

while (fgets(buf, sizeof(buf)-1, infile)) {
if (startofline && PendingBoundary(buf, boundaries, boundaryct)) {
neednewline = 0;
break;
}
if (neednewline) {
putc('\n', outfile);
if (digestp) MD5Update(&context, "\r\n", 2);
}
if (p = strchr(buf, '\n')) {
*p = '\0';
startofline = neednewline = 1;
}
else {
startofline = neednewline = 0;
}
fputs(buf, outfile);
if (digestp) MD5Update(&context, buf, strlen(buf));
}
if (neednewline) {
putc('\n', outfile);
if (digestp) MD5Update(&context, "\r\n", 2);
}
if (digestp) *digestp=md5contextTo64(&context);
}

char *md5digest(infile, len)
FILE *infile;
long *len;
{
MD5_CTX context;
char buf[1000];
long length = 0;
int nbytes;

MD5Init(&context);
while (nbytes = fread(buf, 1, sizeof(buf), infile)) {
length += nbytes;
MD5Update(&context, buf, nbytes);
}
rewind(infile);
if (len) *len = length;
return md5contextTo64(&context);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/macos.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macos.c'\"
else
echo shar: Extracting \"'mpack-1.0/macos.c'\" \(8164 bytes\)
cat >'mpack-1.0/macos.c' <<'END_OF_FILE'
/* macos.c -- operating system dependant mpack code for the Macintosh
*
* (C) Copyright 1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*/

#include <stdio.h>


#include <ctype.h>
#include <string.h>
#include <errno.h>

#include "common.h"
#include "macnapp.h"
#include "macmpack.h"

extern char *malloc(), *realloc();

char *xmalloc(unsigned size)
{
char *ret;

if (ret = malloc((unsigned) size))
return ret;

yell("Virtual memory exhausted");
exit(1);
}

char *xrealloc (char *ptr, unsigned size)
{
char *ret;

/* xrealloc (NULL, size) behaves like xmalloc (size), as in ANSI C */
if (ret = !ptr ? malloc ((unsigned) size) : realloc (ptr, (unsigned) size))
return ret;

yell("Virtual memory exhausted");
exit(1);
}

char *strsave(char *str)
{
char *p = xmalloc(strlen(str)+1);
strcpy(p, str);
return p;
}

/* save output filename buffer */
static char *output_fname = NULL;

/* TMPL resource for IDna -- ID to name mappings
*/
char TMPL[] = {
16 , 'D', 'i', 'r', 'e', 'c', 't', 'o',
'r', 'y', ' ', 'N', 'u', 'm', 'b', 'e',
'r', 'D', 'W', 'R', 'D'
};

/* Generate a message-id */
char *os_genid()
{

char *result;
long tick;
unsigned long time;

tick = TickCount();
result = malloc(64);
GetDateTime(&time);
sprintf(result, "%lu.%lu@random-mac", tick, time);

/* make sure tick count is bumped before we return... */
while (tick == TickCount());

return (result);
}

/* Create and return directory for a message-id
*/
char *os_idtodir(id)
char *id;
{

static PCstr buf[257];
static unsigned char mpackdir[] = "\pmpack-tmp";
PCstr idbuf[257];
char *fname;
short wrefnum, vrefnum, resfile, uqid, createflag = 0;
long dirid, procid;
OSErr err;
Handle h;
ResType type = 'IDna';
FInfo finfo;

/* get name of default volume */
if (GetVol(P(buf), &wrefnum) != noErr) return (NULL);
procid = 0;
if (GetWDInfo(wrefnum, &vrefnum, &dirid, &procid) != noErr) return (NULL);

/* try creating tmp dir */
err = DirCreate(vrefnum, 0, mpackdir, &dirid);
if (err != noErr && err != dupFNErr) return (NULL);
CtoPCstrcat(buf, ":");
PtoPCstrcat(buf, (char *) mpackdir);
CtoPCstrcat(buf, ":");
fname = C(buf) + PCstrlen(buf);

/* open the map file */
strcpy(fname, "map");
SetPlen(buf);
CreateResFile(P(buf));
if ((err = ResError()) == noErr && GetFInfo(P(buf), vrefnum, &finfo) == noErr) {
finfo.fdType = 'rsrc';
finfo.fdCreator = 'RSED';
SetFInfo(P(buf), vrefnum, &finfo);
}
if ((resfile = OpenResFile(P(buf))) < 0) return (NULL);
if (err == noErr && PtrToHand((Ptr) TMPL, &h, sizeof (TMPL)) == noErr) {
AddResource(h, 'TMPL', 1000, "\pIDna");
}

/* is there a mapping for the id? */
CtoPCstrcpy(idbuf, id);
h = GetNamedResource(type, P(idbuf));

/* no mapping -- create one */
if (!h) {
createflag = 1;
while ((uqid = UniqueID(type)) < 128);
h = NewHandle(sizeof (short));
if (h) (**(short **)h) = uqid;
AddResource(h, type, uqid, P(idbuf));
if ((err = ResError()) != noErr) {
CloseResFile(resfile);
return (NULL);
}
} else {
uqid = ** (short **) h;
}

/* set directory name & create it */
sprintf(fname, "%d:", uqid);
SetPlen(buf);
err = DirCreate(vrefnum, 0, P(buf), &dirid);
if (err != noErr && err != dupFNErr) {
RmveResource(h);
DisposHandle(h);
h = NULL;
}

/* done with map file */
CloseResFile(resfile);

return (h ? C(buf) : NULL);
}

/*
* We are done with the directory returned by os_idtodir()
* Remove it
*/
os_donewithdir(dir)
char *dir;
{

PCstr buf[257];
short uqid, resfile;
char *fname;
Handle h;

CtoPCstrcpy(buf, dir);
HDelete(0, 0, P(buf));
fname = strchr(C(buf), ':');
if (fname && (fname = strchr(fname + 1, ':'))) {
uqid = atoi(fname + 1);
strcpy(fname, ":map");
SetPlen(buf);
if ((resfile = OpenResFile(P(buf))) >= 0) {
h = GetResource('IDna', uqid);
if (h) {
RmveResource(h);
DisposHandle(h);
}
CloseResFile(resfile);
}
}
}

/*
* Create a new file, with suggested filename "fname".
* "fname" may have come from an insecure source, so clean it up first.
* It may also be null.
* "contentType" is passed in for use by systems that have typed filesystems.
* "binary" is nonzero if the new file should be opened in binary mode.
*/
FILE *os_newtypedfile(fname, contentType, binary)
char *fname;
char *contentType;
int binary;
{

char *p;


static int filesuffix=0;
char buf[128], *descfname=0;
FILE *outfile = 0;

extern long _ftype, _fcreator;
extern Cursor watch;
Handle h;
PCstr tstr[257];

if (!fname) fname = "";

/* Translate ':' to underscore */
for (p=fname; *p; p++) {
if (*p == ':' || !isprint(*p)) *p = '_';
}

/* chop filename to length */
if (strlen(fname) > 31) {
fname += strlen(fname) - 31;
}

if (!fname[0]) {
do {
if (outfile) fclose(outfile);
sprintf(buf, "part%d", ++filesuffix);
} while (outfile = fopen(buf, "r"));
fname = buf;
}

else if (outfile = fopen(fname, "r")) {
CtoPCstrcpy(tstr, fname);
ParamText(P(tstr), NULL, NULL, NULL);
SetCursor(&arrow);
if (NAalert(replaceALRT) != iReplace) {


do {
fclose(outfile);
sprintf(buf, "%s.%d", fname, ++filesuffix);

} while (outfile = fopen(buf, "r"));
fname = buf;

} else {
fclose(outfile);
}
SetCursor(&watch);
}

/* set the type */
CtoPCstrcpy(tstr, contentType);
h = GetNamedResource('TyCr', P(tstr));
if (h) {
_ftype = (*(OSType **)h)[0];
_fcreator = (*(OSType **)h)[1];
} else {
_ftype = '????';
}

/* save file */
outfile = fopen(fname, "wb");
if (!outfile) {
sprintf(buf, "Couldn't open file %s", fname);
warn(buf);
return (0);
}

if (output_fname) free(output_fname);
output_fname = strsave(fname);

if (strlen(fname) > sizeof(buf)-6) {
descfname = xmalloc(strlen(fname)+6);
}
else {
descfname = buf;
}
strcpy(descfname, fname);

if (p = strrchr(descfname, '.')) *p = '\0';

strcat(descfname, ".desc");


(void) rename(TEMPFILENAME, descfname);
if (descfname != buf) free(descfname);

CtoPstr(descfname);
_ftype = 'TEXT';
_fcreator = 'mPAK';

return outfile;
}

/*
* Warn user that the MD5 digest of the last file created by os_newtypedfile()
* did not match that supplied in the Content-MD5: header.
*/
os_warnMD5mismatch()
{
char *warning;

warning = xmalloc(strlen(output_fname) + 100);
sprintf(warning, "%s was corrupted in transit",
output_fname);
warn(warning);
free(warning);
}

/* bring up an error dialog for a file error
*/
void os_perror(char *str)
{
extern int errno;
char *err = strerror(errno), *scan;
char msg[256];
short maxflen;

maxflen = 255 - (strlen(err) + 2);
if (strlen(str) > maxflen) {
str += strlen(str) - maxflen;
for (scan = str; *scan && *scan++ != ':';);
if (*scan) str = scan;
}
sprintf(msg, "%s: %s", str, err);
yell(msg);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/dospk.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/dospk.c'\"
else
echo shar: Extracting \"'mpack-1.0/dospk.c'\" \(3552 bytes\)
cat >'mpack-1.0/dospk.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers

* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the

* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*


* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "version.h"
#include "xmalloc.h"

#define MAXADDRESS 100

extern int errno;
extern int optind;
extern char *optarg;

main(argc, argv)
int argc;
char **argv;
{
int opt;
char *fname = 0;
char *subject = 0;
char *descfname = 0;
long maxsize = 60000;
char *outfname = 0;
char *ctype = 0;
char *headers = 0;
int i;
char *p;
char sbuf[1024];
char fnamebuf[4096];
int part;
FILE *infile;

if ((p = getenv("SPLITSIZE")) && *p >= '0' && *p <= '9') {
maxsize = atoi(p);
}

while ((opt = getopt(argc, argv, "s:d:m:c:o:n:")) != EOF) {
switch (opt) {
case 's':
subject = optarg;
break;

case 'd':
descfname = optarg;
break;

case 'm':
maxsize = atol(optarg);
break;

case 'c':
ctype = optarg;
break;

case 'o':
outfname = optarg;
break;

default:
usage();

}
}

if (ctype) {
if (!cistrncmp(ctype, "text/")) {
fprintf(stderr, "This program is not appropriate for encoding textual data\n");
exit(1);
}
if (cistrncmp(ctype, "application/", 12) && cistrncmp(ctype, "audio/", 6) &&
cistrncmp(ctype, "image/", 6) && cistrncmp(ctype, "video/", 6)) {
fprintf(stderr, "Content type must be subtype of application, audio, image, or video\n");
exit(1);
}
}

if (!outfname) {
fprintf(stderr, "The -o switch is required\n");
usage();
}

if (optind == argc) {
fprintf(stderr, "An input file must be specified\n");
usage();
}
fname = argv[optind++];


for (p = fname; *p; p++) {

if (isupper(*p)) *p = tolower(*p);
}

/* Must have -o */
if (optind != argc) {
fprintf(stderr, "Too many arguments\n");
usage();
}

if (!subject) {
fputs("Subject: ", stdout);
fflush(stdout);
if (!fgets(sbuf, sizeof(sbuf), stdin)) {
fprintf(stderr, "A subject is required\n");
usage();
}
if (p = strchr(sbuf, '\n')) *p = '\0';
subject = sbuf;
}

if (encode(fname, descfname, subject, headers, maxsize, ctype, outfname)) exit(1);

exit(0);
}

usage()
{
fprintf(stderr, "mpack version %s\n", MPACK_VERSION);
fprintf(stderr,
"usage: mpack [-s subj] [-d file] [-m maxsize] [-c content-type] -o output file\n");
exit(1);
}

warn()
{
abort();
}
END_OF_FILE
fi
echo 'End of part 4 (of 6).'
echo 04 >> _shar_private

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:38:02 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 62
Archive-name: mpack-1.0/05

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:

# "End of part 5 (of 6)."


# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'

if test -f 'mpack-1.0/md5c.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/md5c.c'\"
else
echo shar: Extracting \"'mpack-1.0/md5c.c'\" \(10405 bytes\)
cat >'mpack-1.0/md5c.c' <<'END_OF_FILE'
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.

License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.

License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.

RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.

These notices must be retained in any copies of any part of this
documentation and/or software.
*/

#include "md5.h"

/* Constants for MD5Transform routine.
*/

#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));

static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}

/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}

/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;

/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);

/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);

partLen = 64 - index;

/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);

for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);

index = 0;
}
else
i = 0;

/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;

/* Save number of bits */
Encode (bits, context->count, 8);

/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);

/* Append length (before padding) */
MD5Update (context, bits, 8);

/* Store state in digest */
Encode (digest, context->state, 16);

/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}

/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

Decode (x, block, 64);

/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;

/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}

/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;

for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}

/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;

for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}

/* Note: Replace "for loop" with standard memcpy if possible.
*/

static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
unsigned int i;

for (i = 0; i < len; i++)
output[i] = input[i];
}

/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
unsigned int i;

for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
END_OF_FILE
fi
if test -f 'mpack-1.0/uudecode.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/uudecode.c'\"
else
echo shar: Extracting \"'mpack-1.0/uudecode.c'\" \(8440 bytes\)
cat >'mpack-1.0/uudecode.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#include <ctype.h>
#include "xmalloc.h"
#include "common.h"

extern char *os_idtodir();
extern FILE *os_newtypedfile();

/*
* Read an input file, looking for data in split-uuencode format
*/
handleUuencode(infile, subject)
FILE *infile;
char *subject;
{
char *fname;
int part = 0, nparts = 0;
char *dir;
char buf[1024];
FILE *partfile;

if (parseSubject(subject, &fname, &part, &nparts)) return 0;

/* Create directory to store parts and copy this part there. */
dir = os_idtodir(fname);
if (!dir) return 1;
sprintf(buf, "%s%d", dir, part);


partfile = fopen(buf, "w");
if (!partfile) {
os_perror(buf);

return 1;
}
while (fgets(buf, sizeof(buf), infile)) {
fputs(buf, partfile);
}
fclose(partfile);

/* Check to see if we have all parts. Start from the highest numbers
* as we are more likely not to have them.
*/

for (part = nparts; part; part--) {
sprintf(buf, "%s%d", dir, part);


partfile = fopen(buf, "r");
if (partfile) {
fclose(partfile);
}
else {

return 0;
}
}

return uudecodefiles(dir, nparts);
}

/*
* Parse a Subject: header, looking for clues with which to decode
* split-uuencoded data.
*/
int
parseSubject(subject, fnamep, partp, npartsp)
char *subject;
char **fnamep;
int *partp;
int *npartsp;
{
char *scan, *bak;
int part = 0, nparts = 0;

/* Skip leading whitespace and other garbage */
scan = subject;
while (isspace(*scan) || *scan == '-') scan++;
if (!cistrncmp(scan, "repost", 6)) {
for (scan += 6; isspace(*scan) || *scan == ':' || *scan == '-'; scan++);
}

/* Replies aren't usually data */
if (!cistrncmp(scan, "re:", 3)) return 1;

/* Get filename */
*fnamep = scan;
while (isalnum(*scan) || *scan == '-' || *scan == '+' || *scan == '&'
|| *scan == '_' || *scan == '.') scan++;
if (*fnamep == scan || !*scan) return 1;
*scan++ = '\0';

/* Get part number */
while (*scan) {
/* look for "1/6" or "1 / 6" or "1 of 6" or "1o6" */
if (isdigit(*scan) &&
(scan[1] == '/'
|| (scan[1] == ' ' && scan[2] == '/')
|| (scan[1] == ' ' && scan[2] == 'o' && scan[3] == 'f')
|| (scan[1] == '-' && scan[2] == 'o' && scan[3] == 'f')
|| (scan[1] == 'o' && isdigit(scan[2])))) {
while (isdigit(scan[-1])) scan--;
part = 0;
while (isdigit(*scan)) {
part = part * 10 + *scan++ - '0';
}
while (scan != '\0' && !isdigit(*scan)) scan++;
if (isdigit(*scan)) {
nparts = 0;
while (isdigit(*scan)) {
nparts = nparts * 10 + *scan++ - '0';
}
}
break;
}

/* look for "6 parts" or "part 1" */
if (!cistrncmp("part", scan, 4)) {
if (scan[4] == 's') {
for (bak = scan; bak >= subject && !isdigit(*bak); bak--);
if (bak > subject) {
while (bak > subject && isdigit(bak[-1])) bak--;
nparts = 0;
while (isdigit(*bak)) {
nparts = nparts * 10 + *bak++ - '0';
}
}
} else {
while (*scan != '\0' && !isdigit(*scan)) scan++;
part = 0;
while (isdigit(*scan)) {
part = part * 10 + *scan++ - '0';
}
scan -= 2;
}
}
scan++;
}

if (nparts == 0 || part == 0 || part > nparts) return 1;
*partp = part;
*npartsp = nparts;
return 0;
}

/* Length of a normal uuencoded line, including newline */
#define UULENGTH 62

/*
* Decode the uuencoded file that is in 'nparts' pieces in 'dir'.
*/
int
uudecodefiles(dir, nparts)
char *dir;
int nparts;
{
int part;
enum {st_start, st_desc, st_inactive, st_decode, st_nextlast, st_last} state;
FILE *infile;
FILE *outfile;
char buf[1024];
char lastline[UULENGTH+1];
char *fname, *p;
char *contentType = "application/octet-stream";

/* Create description filename */
outfile = fopen(TEMPFILENAME, "w");
state = outfile ? st_desc : st_start;

/* Handle each part in order */
for (part = 1; part <= nparts; part++) {
sprintf(buf, "%s%d", dir, part);
infile = fopen(buf, "r");
if (!infile) {
os_perror(buf);
if (outfile) fclose(outfile);
remove(TEMPFILENAME);
return 1;
}

while (fgets(buf, sizeof(buf), infile)) {
switch (state) {
case st_desc: /* Copying description text */
if (!strncmp(buf, "-----", 5) ||
!strncmp(buf, "#!", 2) ||
!cistrncmp(buf, "part=", 5) ||
!cistrncmp(buf, "begin", 5)) {
fclose(outfile);
outfile = 0;
state = st_start;
}
else {
fputs(buf, outfile);


break;
}
/* FALL THROUGH */

case st_start: /* Looking for start of uuencoded file */
if (strncmp(buf, "begin ", 6)) break;
/* skip mode */
p = buf + 6;
while (*p && !isspace(*p)) p++;
while (*p && isspace(*p)) p++;
fname = p;
while (*p && !isspace(*p)) p++;
*p = '\0';
if (!*fname) return 1;

/* Guess the content-type of common filename extensions */
if (strlen(fname) > 4) {
p = fname + strlen(fname)-4;
if (!cistrcmp(p, ".gif")) contentType = "image/gif";
if (!cistrcmp(p, ".jpg")) contentType = "image/jpeg";
if (!cistrcmp(p, ".jpeg")) contentType = "image/jpeg";
if (!cistrcmp(p, ".mpg")) contentType = "video/mpeg";
if (!cistrcmp(p, ".mpeg")) contentType = "video/mpeg";
}

/* Create output file and start decoding */
outfile = os_newtypedfile(fname, contentType, 1);
if (!outfile) {
fclose(infile);
return 1;
}
state = st_decode;
break;

case st_inactive: /* Looking for uuencoded data to resume */
if (*buf != 'M' || strlen(buf) != UULENGTH) break;
state = st_decode;
/* FALL THROUGH */
case st_decode: /* Decoding data */
if (*buf == 'M' && strlen(buf) == UULENGTH) {
uudecodeline(buf, outfile);
break;
}
if (strlen(buf) > UULENGTH) {
state = st_inactive;
break;
}
/*
* May be on nearing end of file.
* Save this line in case we are.
*/
strcpy(lastline, buf);
if (*buf == ' ' || *buf == '`') {
state = st_last;
}
else {
state = st_nextlast;
}
break;

case st_nextlast: /* May be nearing end of file */
if (*buf == ' ' || *buf == '`') {
state = st_last;
}
else {
state = st_inactive;
}
break;

case st_last: /* Should be at end of file */
if (strcmp(buf, "end\n")) {
/* Handle that last line we saved */
uudecodeline(lastline, outfile);
fclose(infile);
fclose(outfile);
for (;part <= nparts; part++) {
sprintf(buf, "%s%d", dir, part);
remove(buf);
}
os_donewithdir(dir);
return 0;
}
state = st_inactive;
break;
}
}
state = st_inactive;
fclose(infile);
sprintf(buf, "%s%d", dir, part);
remove(buf);
}
if (outfile) fclose(outfile);
os_donewithdir(dir);
return 0;
}

#define DEC(c) (((c) - ' ') & 077)

/*
* Decode a uuencoded line to 'outfile'
*/
uudecodeline(line, outfile)
char *line;
FILE *outfile;
{
int c, len;

len = DEC(*line++);
while (len) {
c = DEC(*line) << 2 | DEC(line[1]) >> 4;
putc(c, outfile);
if (--len) {
c = DEC(line[1]) << 4 | DEC(line[2]) >> 2;
putc(c, outfile);
if (--len) {
c = DEC(line[2]) << 6 | DEC(line[3]);
putc(c, outfile);
len--;
}
}
line += 4;
}
return;
}


END_OF_FILE
fi
if test -f 'mpack-1.0/encode.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/encode.c'\"
else
echo shar: Extracting \"'mpack-1.0/encode.c'\" \(5903 bytes\)
cat >'mpack-1.0/encode.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#include <string.h>

extern char *magic_look();
extern char *os_genid();
extern char *md5digest();

#define NUMREFERENCES 4

/*
* Encode a file named into one or more MIME messages, each
* no larger than 'maxsize'. A 'maxsize' of zero means no size limit.
*/
int encode(fname, descfname, subject, headers, maxsize, typeoverride, outfname)
char *fname, *descfname, *subject, *headers;
long maxsize;
char *typeoverride, *outfname;
{
char *type;
FILE *infile, *descfile, *outfile;
char *cleanfname, *p;
char *digest;
long filesize, l, written;
int thispart, numparts = 1;
char *multipartid, *msgid, *referenceid[NUMREFERENCES];
char buf[1024];
int i;

/* Open files */
infile = fopen(fname, "rb");
if (!infile) {
os_perror(fname);
return 1;
}
if (descfname) {
descfile = fopen(descfname, "r");
if (!descfile) {
os_perror(descfname);
return 1;
}
}

/* Clean up fname for printing */
cleanfname = fname;
if (p = strrchr(cleanfname, '/')) cleanfname = p+1;
if (p = strrchr(cleanfname, '\\')) cleanfname = p+1;
if (p = strrchr(cleanfname, ':')) cleanfname = p+1;

/* Find file type */
if (typeoverride) {
type = typeoverride;
}
else {
type = magic_look(infile);
}

/* Compute MD5 digest */
digest = md5digest(infile, &filesize);

/* See if we have to do multipart */
if (maxsize) {
filesize = (filesize / 54) * 73; /* Allow for base64 expansion */

/* Add in size of desc file */
if (descfname) {
free(md5digest(descfile, &l)); /* XXX */
filesize += l;
}

numparts = (filesize-1000)/maxsize + 1;
if (numparts < 1) numparts = 1;
}

multipartid = os_genid();
for (i=0; i<NUMREFERENCES; i++) {
referenceid[i] = 0;
}

for (thispart=1; thispart <= numparts; thispart++) {
written = 0;

/* Open output file */
if (numparts == 1) {
outfile = fopen(outfname, "w");
if (!outfile) os_perror(outfname);
}
else {
sprintf(buf, "%s.%02d", outfname, thispart);


outfile = fopen(buf, "w");
if (!outfile) os_perror(buf);
}

if (!outfile) return 1;

msgid = os_genid();
fprintf(outfile, "Message-ID: <%s>\n", msgid);
fprintf(outfile, "Mime-Version: 1.0\n");
if (headers) fputs(headers, outfile);
if (numparts > 1) {
fprintf(outfile, "Subject: %s (%02d/%02d)\n", subject,
thispart, numparts);
if (thispart == 1) {
referenceid[0] = msgid;
}
else {
/* Put out References: header pointing to previous parts */
fprintf(outfile, "References: <%s>\n", referenceid[0]);
for (i=1; i<NUMREFERENCES; i++) {
if (referenceid[i]) fprintf(outfile, "\t<%s>\n",
referenceid[i]);
}
for (i=2; i<NUMREFERENCES; i++) {
referenceid[i-1] = referenceid[i];
}
referenceid[NUMREFERENCES-1] = msgid;
}
fprintf(outfile,
"Content-Type: message/partial; number=%d; total=%d;\n",
thispart, numparts);
fprintf(outfile, "\tid=\"%s\"\n", multipartid);
fprintf(outfile, "\n");
}

if (thispart == 1) {
if (numparts > 1) {
fprintf(outfile, "Message-ID: <%s>\n", multipartid);
fprintf(outfile, "MIME-Version: 1.0\n");
}
fprintf(outfile, "Subject: %s\n", subject);
fprintf(outfile,
"Content-Type: multipart/mixed; boundary=\"-\"\n");
fprintf(outfile,
"\nThis is a MIME encoded message. Decode it with \"munpack\"\n");
fprintf(outfile,
"or any other MIME reading software. Mpack/munpack is available\n");
fprintf(outfile,
"in Volume 3 of comp.sources.reviewed or via anonymous FTP in\n");
fprintf(outfile, "export.acs.cmu.edu:pub/mpack/\n");
written = 300;

/* Spit out description section */
if (descfname) {
fprintf(outfile, "---\n\n");
while (fgets(buf, sizeof(buf), descfile)) {
/* Strip multiple leading dashes as they may become MIME
* boundaries
*/
p = buf;
if (*p == '-') {
while (p[1] == '-') p++;
}

fputs(p, outfile);
written += strlen(p);
}
fprintf(outfile, "\n");
fclose(descfile);
}

fprintf(outfile, "---\n");
fprintf(outfile, "Content-Type: %s; name=\"%s\"\n", type, cleanfname);
fprintf(outfile, "Content-Transfer-Encoding: base64\n");
fprintf(outfile, "Content-Disposition: inline; filename=\"%s\"\n",
cleanfname);
fprintf(outfile, "Content-MD5: %s\n\n", digest);
free(digest);
written += 80;
}

if (written == maxsize) written--; /* avoid a nasty fencepost error */

to64(infile, outfile, (thispart == numparts) ? 0 : (maxsize-written));

if (thispart == numparts) {
fprintf(outfile, "\n-----\n");
}

fclose(outfile);
}

return 0;
}
END_OF_FILE
fi
if test -f 'mpack-1.0/macnclip.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macnclip.c'\"
else
echo shar: Extracting \"'mpack-1.0/macnclip.c'\" \(5723 bytes\)
cat >'mpack-1.0/macnclip.c' <<'END_OF_FILE'
/* macnclip.c -- clipboard window for nifty application library
*
* (C) Copyright 1990-1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*/

#include "macnapp.h"
#ifndef THINK_C
#include <Resources.h>
#include <Fonts.h>
#include <Scrap.h>
#endif

typedef struct clipinfo {
nate_win winp;
Handle data;
ResType type, preftype;
short scrapc;
Boolean valid;
} clipinfo;

/* handle to cliboard window */
static na_win **cliph = (na_win**) NULL;
static WORD menuid, itemid;

/* function prototypes */
static short clipclose(na_win*);
static short clipupdate(na_win*, Boolean);
static short cliptask(na_win*);
static short clipinit(na_win*, long*);

#define cinfo ((clipinfo *) winp)
#define teinfo ((nate_win *) winp)

/* close the clipboard window
*/
static short clipclose(winp)
na_win *winp;
{
Handle hand;

cliph = (na_win**) NULL;
if (menuid) CheckItem(GetMHandle(menuid), itemid, false);
if ((hand = cinfo->data) != (Handle) NULL) {
DisposHandle(hand);
} else {
NATEclosep(winp);
}

return (NA_CLOSED);
}

/* update the clipboard window -- this does all the work
*/
#ifdef __STDC__
static short clipupdate(na_win *winp, Boolean newsize)
#else
static short clipupdate(winp, newsize)


na_win *winp;
Boolean newsize;
#endif
{

long len;
long offset;

if (!cinfo->valid) {
winp->ctrlp = NULL;
winp->activep = NULL;
winp->idlep = NULL;
winp->mousep = NULL;
winp->cursorp = NULL;
if (teinfo->vctrl != (ControlHandle) NULL) {
DisposeControl(teinfo->vctrl);
teinfo->vctrl = (ControlHandle) NULL;


}
if (winp->cursorRgn != (RgnHandle) NULL) {
DisposeRgn(winp->cursorRgn);

winp->cursorRgn = NULL;


if (winp->flags & NA_CURSORON) SetCursor(&QD(arrow));
}

cinfo->scrapc = InfoScrap()->scrapCount;
if (cinfo->data == (Handle) NULL) {
cinfo->data = NewHandle(0);
if (MemError() != noErr) return (NA_NOTPROCESSED);
}
if ((len = GetScrap(cinfo->data, cinfo->type = cinfo->preftype, &offset)) <= 0) {
if ((len = GetScrap(cinfo->data, cinfo->type =
(cinfo->preftype == 'TEXT' ? 'PICT' : 'TEXT'), &offset)) <= 0) {
return (NA_NOTPROCESSED);
}
}
if (cinfo->type == 'TEXT') {
HLock(cinfo->data);
NATEinit(winp, NATE_READONLY | NATE_NOMOUSE | NATE_NOHSCROLL, 0, *cinfo->data, len);
winp->updatep = clipupdate;
winp->closep = clipclose;
winp->menup = NULL;
HUnlock(cinfo->data);
DisposHandle(cinfo->data);
cinfo->data = (Handle) NULL;
}
newsize = true;
cinfo->valid = true;
}

if (cinfo->type == 'TEXT') return (NATEupdatep(winp, newsize));
{
Rect rtemp = (*(PicHandle)cinfo->data)->picFrame;

DrawPicture((PicHandle) cinfo->data, &rtemp);
}

return (NA_NOTPROCESSED);
}

/* watch for the clipboard to change
*/
static short cliptask(winp)
na_win *winp;
{
if (cinfo->scrapc != InfoScrap()->scrapCount) {
cinfo->valid = false;
InvalRect(&winp->pwin->portRect);
}

return (NA_PROCESSED);
}

/* initialize the clipboard window
*/
static short clipinit(winp, data)
na_win *winp;
long *data;
{
cliph = (na_win**) RecoverHandle((Ptr) winp);
TextFont(monaco);
TextSize(9);
winp->type = NA_CLIPTYPE;
ShowWindow(winp->pwin);
winp->updatep = clipupdate;
winp->closep = clipclose;
winp->taskp = cliptask;
teinfo->vctrl = (ControlHandle) NULL;

return (NA_PROCESSED);
}

/* turn on/off the clipboard window
*/
#ifdef __STDC__
void NAclipboard(Boolean show, ResType preftype)
#else
void NAclipboard(show, preftype)
Boolean show;
ResType preftype;
#endif
{
clipinfo cinfob;

if ((cliph == (na_win**) NULL && !show) || (cliph != (na_win**) NULL && show)) {
return;
}
if (!show) {
NAcloseWindow(NAlockWindow(cliph), NA_REQCLOSE);
return;
}
cinfob.data = (Handle) NULL;
cinfob.scrapc = 0;
cinfob.valid = false;
cinfob.preftype = preftype;
NAwindow(NAscreenrect(NA_VQUARTERSCN | NA_H3QUARTERSCN | NA_LEFTSCN | NA_BOTTOMSCN),
NA_USERESOURCE | NA_HASCONTROLS | NA_HILITECTRLS | NA_HASTASK | NA_CLOSEBOX | NA_GROWBOX
| NA_FORCESIZE | NA_COPYDATA, NULL, NA_CLIPWINDOW,
(long *) ((char *) &cinfob + sizeof (na_win)), sizeof (cinfob), clipinit);
}

/* deal with a menu selection of the "Show/Hide Clipboard" item
*/
#ifdef __STDC__
void NAclipboardMenu(WORD menu, WORD item, ResType preftype)
#else
void NAclipboardMenu(menu, item, preftype)
WORD menu, item;
ResType preftype;
#endif
{
Boolean show;

CheckItem(GetMHandle(menuid = menu), itemid = item,
show = (cliph == (na_win**) NULL ? true : false));
NAclipboard(show, preftype);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/macndlog.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macndlog.c'\"
else
echo shar: Extracting \"'mpack-1.0/macndlog.c'\" \(6070 bytes\)
cat >'mpack-1.0/macndlog.c' <<'END_OF_FILE'
/* macndlog.c -- dialog utilities for nifty application library
*
* (C) Copyright 1990-1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*/

#include "macnapp.h"
#ifndef THINK_C
#include <ToolUtils.h>
#endif

/* place to save modifiers from a modal dialog */
static short dialog_modifiers;

/* a filter proc which handles Return, Enter, Esc, command-period properly
*/

pascal Boolean NAfilterProc(dialog, pevent, item)


DialogPtr dialog;
EventRecord *pevent;
short *item;
{

dialog_modifiers = pevent->modifiers;


if (pevent->what == autoKey || pevent->what == keyDown) {

switch (pevent->message & charCodeMask) {
case '\r':
case '\n':


*item = 1;
goto HILITE;

case '.':
if (!(pevent->modifiers & cmdKey)) break;
case '\033':
*item = 2;
HILITE:
NAflashButton(dialog, *item);
return (true);
}
}

return (false);
}

/* send events from a modal dialog box to the control procedure.
* if no ctrlp in window structure, then a simple OK/CANCEL box is assumed.
* returns item number of last item event.
*/
short NAmodalLoop(winp)
na_win *winp;
{
short item;
short status = NA_NOTPROCESSED;
ControlHandle ctrl;
Point pt;

* (long *) &pt = 0L;
do {
ModalDialog(NAfilterProc, &item);
if (winp->ctrlp == (na_ctrlp) NULL) {
if (item == iOk || item == iCancel) break;
} else {
NAgetDHandle(winp->pwin, item, &ctrl);
status = (*winp->ctrlp)(winp, pt, item, dialog_modifiers, ctrl);
}
} while (status >= NA_NOTPROCESSED);

return (item);
}

/* enable/disable a control in a dialog window
*/
#ifdef __STDC__
void NAenableDItem(DialogPtr dialog, short item, Boolean on)
#else
void NAenableDItem(dialog, item, on)
DialogPtr dialog;
short item;
Boolean on;
#endif
{
short type;
Handle ctrl;
short ty;
Rect box;

GetDItem(dialog, item, &ty, &ctrl, &box);
type = ty;
if (on) type &= ~itemDisable;
else type |= itemDisable;
if (type == statText) type = editText;
if (type == editText | itemDisable) type = statText;
SetDItem(dialog, item, type, ctrl, &box);
}

/* hilite a control in a dialog window
*/
#ifdef __STDC__
void NAhiliteDItem(DialogPtr dialog, short item, short how)
#else
void NAhiliteDItem(dialog, item, how)
DialogPtr dialog;
short item;
short how;
#endif
{
Handle ctrl;
short type;
Rect box;
PenState tmpPen;



GetDItem(dialog, item, &type, &ctrl, &box);

if (type & ctrlItem) {
HiliteControl((ControlHandle) ctrl, how);
} else if (type & (statText | editText) && how == 255) {
GetPenState(&tmpPen);
PenNormal();
PenPat(QD(gray));
if (type & statText) {
PenMode(patBic);
PaintRect(&box);
} else {
InsetRect(&box, -3, -3);
FrameRect(&box);
}
SetPenState(&tmpPen);
}
}

/* make an item visible/invisible in a dialog window
*/
#ifdef __STDC__
void NAvisibleDItem(DialogPtr dialog, short item, Boolean show)
#else
void NAvisibleDItem(dialog, item, show)
DialogPtr dialog;
short item;
Boolean show;
#endif
{
if (show) ShowDItem(dialog, item);
else HideDItem(dialog, item);
}

/* set the text in a dialog item
*/
#ifdef __STDC__
void NAsetIText(DialogPtr dialog, short item, PCstr *str)
#else
void NAsetIText(dialog, item, str)
DialogPtr dialog;
short item;
PCstr *str;
#endif
{
Handle texth;

NAgetDHandle(dialog, item, &texth);
SetIText(texth, str);
}

/* get the text in a dialog item
*/
#ifdef __STDC__
void NAgetIText(DialogPtr dialog, short item, PCstr *str)
#else
void NAgetIText(dialog, item, str)
DialogPtr dialog;
short item;
PCstr *str;
#endif
{
Handle texth;

NAgetDHandle(dialog, item, &texth);
GetIText(texth, str);
SetClen(str);
}

/* set the appropriate radio buttons
*/
#ifdef __STDC__
short NAradioSet(DialogPtr dialog, short firstitem, short lastitem, short setting)
#else
short NAradioSet(dialog, firstitem, lastitem, setting)
DialogPtr dialog;
short firstitem;
short lastitem;
short setting;
#endif
{
short item;
ControlHandle ctrl;

for (item = firstitem; item <= lastitem; item++) {
NAgetDHandle(dialog, item, &ctrl);
SetCtlValue(ctrl, item == setting ? 1 : 0);
}

return (setting - firstitem);
}

/* an alert window with built-in param text calls
*/
#ifdef __STDC__
short NAalertParam(short alert, short strlist, short str1, short str2, short str3, short str4)
#else
short NAalertParam(alert, strlist, str1, str2, str3, str4)
short alert, strlist, str1, str2, str3, str4;
#endif
{
PCstr *param1 = NULL, *param2 = NULL, *param3 = NULL, *param4 = NULL;
PCstr store1[257], store2[257], store3[257], store4[257];

if (str1) GetIndString(param1 = store1, strlist, str1);
if (str2) GetIndString(param2 = store2, strlist, str2);
if (str3) GetIndString(param3 = store3, strlist, str3);
if (str4) GetIndString(param4 = store4, strlist, str4);
ParamText(param1, param2, param3, param4);

return (NAalert(alert));
}
END_OF_FILE
fi
if test -f 'mpack-1.0/macninit.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macninit.c'\"
else
echo shar: Extracting \"'mpack-1.0/macninit.c'\" \(5436 bytes\)
cat >'mpack-1.0/macninit.c' <<'END_OF_FILE'
/* macninit.c -- general mac nifty application library initialization
*
* (C) Copyright 1990-1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*/

#ifndef THINK_C
#include <Fonts.h>
#include <SegLoad.h>
#include <OSEvents.h>

extern void _DataInit(); /* MPW initialize routine */
#endif
#include <Traps.h>
#include <AppleEvents.h>
#include <GestaltEqu.h>
#include "macnapp.h"

extern pascal OSErr NArequiredAE(AppleEvent *, AppleEvent *, long);

#ifndef _Unimplemented
#define _Unimplemented 0xA89F
#endif
#ifndef _WaitNextEvent
#define _WaitNextEvent 0xA860
#endif
#ifndef _Gestalt
#define _Gestalt 0xA1AD
#endif

/* global to hold the application heap zone */
extern THz NAappzone;

static Boolean TrapAvailable(short);

/* this checks if a given trap is available on the system
*/
static Boolean TrapAvailable(short tNumber)
{
short numtraps = 0x400;
TrapType tType;

tType = tNumber & 0x800 ? ToolTrap : OSTrap;
if (tType == ToolTrap) {
if (NGetTrapAddress(_InitGraf, ToolTrap)
== NGetTrapAddress(0xAA6E, ToolTrap)) {
numtraps = 0x200;
}
tNumber = tNumber & 0x07FF;
if (tNumber >= numtraps)
tNumber = _Unimplemented;
}

return (NGetTrapAddress(tNumber, tType)
!= NGetTrapAddress(_Unimplemented, ToolTrap));
}

/* initialize the Macintosh managers and niftyapp internal variables.

* call this first. You may wish to call MoreMasters() after this.
*/
short NAinit(short minK, short masters, na_openp openp, na_menup menup,
short numapple, short newitem, short closeitem)
{
long total, contig, response;
EventRecord event;
short count;
Handle menuBar;
short message, i, aeflag = 0;
AppFile afile;
FSSpec fspec;

#ifndef THINK_C
UnloadSeg((Ptr) _DataInit); /* unload MPW init routine */
#endif
MaxApplZone(); /* expand heap so code loads at top */

/* initialize all the managers */
InitGraf((Ptr) &QD(thePort));
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();

/* allocate enough master pointers */
for (count = 1; count <= masters; count++) {
MoreMasters();
if (MemError() != noErr) return (-1);
}

/* hack to bring to front in MultiFinder */
for (count = 1; count <= 3; count++) EventAvail(everyEvent, &event);

/* get the system environment */
(void) SysEnvirons(1, &NAsysenv);

/* verify we have 128K ROMS, WaitNextEvent is available, and we have enough memory */
if (NAsysenv.machineType < 0
|| !TrapAvailable(_WaitNextEvent)
|| (long) GetApplLimit() - (long) ApplicZone() < minK) {
return (-1);
}

/* check for Gestalt and set up Apple Event Handler */
NAgestaltBits = 0;
if (TrapAvailable(_Gestalt)) {
NAgestaltBits = NA_HASGESTALT;
if (Gestalt(gestaltAppleEventsAttr, &response) == noErr) {
NAgestaltBits |= NA_HASAEVENTS;
if (AEInstallEventHandler(kCoreEventClass, typeWildCard,
NArequiredAE, (long) openp, FALSE) == noErr) {
aeflag = 1;
}
}
}

/* clean up and check available free memory */
PurgeSpace(&total, &contig);
if (total < minK) return (-1);

/* store our application heap zone */
NAappzone = ApplicZone();

/* if the user wants automatic menu handling, do it now */
if (menup != (na_menup) NULL) {
if ((menuBar = GetNewMBar(NA_MBAR)) == (Handle) NULL)
return (-1);
SetMenuBar(menuBar);
DisposHandle(menuBar);
AddResMenu(GetMHandle(mApple), 'DRVR');
DrawMenuBar();
NAcloseitem = closeitem;
NAnewitem = newitem;
NAappleitems = numapple;
NAhasedit = true;
NAmenup = menup;
}

/* create full region */
SetRectRgn(NAfullRgn = NewRgn(), -32767, -32767, 32767, 32767);
NAnullRgn = NewRgn();

/* save ibeam cursor */
NAibeam = **GetCursor(iBeamCursor);

/* handle startup files */
if (!aeflag) {
count = 0;
if (openp != (na_openp) NULL) {
CountAppFiles(&message, &count);
if (count) {
for (i = 1; i <= count; i++) {
GetAppFiles(i, &afile);
if ((*openp)(message, &afile, 0) < 0) break;
}
ClrAppFiles(count);
if (message == appPrint
&& NAcloseWindows(NAhead, NA_REQCLOSEALL) == NA_ALLCLOSED) {
return (1);
}
}
}
if (newitem && !count && menup != (na_menup) NULL) {
(*menup)(NULL, mFile, newitem);
}
}

return (0);
}
END_OF_FILE
fi
if test -f 'mpack-1.0/dosunpk.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/dosunpk.c'\"
else
echo shar: Extracting \"'mpack-1.0/dosunpk.c'\" \(2853 bytes\)
cat >'mpack-1.0/dosunpk.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#include <dir.h>
#include <errno.h>
#include "version.h"

extern int optind;
extern char *optarg;

extern int overwrite_files;

main(argc, argv)
int argc;
char **argv;
{
int opt;

FILE *file;
char *p, *q, *path = 0;
int done, gotone;
struct ffblk ffblk;

while ((opt = getopt(argc, argv, "fC:")) != EOF) {
switch (opt) {
case 'f':
overwrite_files = 1;
break;

case 'C':
if (chdir(optarg)) {
perror(optarg);
exit(1);
}
break;

default:
usage();
}
}

if (optind == argc) {
fprintf(stderr, "munpack: reading from standard input\n");
handleMessage(stdin, "text/plain", 0);
exit(0);
}

while (argv[optind]) {
if (path) free(path);
path = 0;

p = argv[optind];
if (p[1] == ':') p += 2;
if (q = strrchr(p, '\\')) p = q+1;
if (q = strrchr(p, '/')) p = q+1;

if (p != argv[optind]) {
path = xmalloc(strlen(argv[optind])+20);
strcpy(path, argv[optind]);
p = path + (p - argv[optind]);
}

gotone = 0;
done = findfirst(argv[optind], &ffblk, 0);
while (!done) {
if (path) strcpy(p, ffblk.ff_name);
file = fopen(path ? path : ffblk.ff_name, "r");
if (!file) {
perror(path ? path : ffblk.ff_name);
}
else {
handleMessage(file, "text/plain", 0);
fclose(file);
}
gotone = 1;
done = findnext(&ffblk);
}
if (!gotone) {
perror(argv[optind]);
}
optind++;
}
exit(0);
}

usage() {
fprintf(stderr, "usage: munpack [-C directory] [files...]\n");
exit(1);
}

warn(s)
char *s;
{
fprintf(stderr, "munpack version %s\n", MPACK_VERSION);
fprintf(stderr, "munpack: warning: %s\n", s);
}
END_OF_FILE
fi
echo 'End of part 5 (of 6).'
echo 05 >> _shar_private

Kevin Braunsdorf

unread,
Sep 24, 1993, 9:40:48 PM9/24/93
to
Submitted-by: John Gardiner Myers <jg...@cmu.edu>
Posting-number: Volume 3, Issue 63
Archive-name: mpack-1.0/06

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file". If this archive is complete, you
# will see the following message at the end:

# "End of part 6 (of 6)."


# created by c...@staff.cc.purdue.edu on Fri Sep 24 19:36:17 1993
# using nushar, by Ben Jackson <b...@ben.com>
PATH=/usr/5bin:/bin:/usr/bin:/usr/ucb:/usr/etc ; export PATH
[ ! -d 'mpack-1.0' ] && echo Creating dir \"'mpack-1.0'\" && mkdir 'mpack-1.0'

if test -f 'mpack-1.0/macpcstr.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macpcstr.c'\"
else
echo shar: Extracting \"'mpack-1.0/macpcstr.c'\" \(6942 bytes\)
cat >'mpack-1.0/macpcstr.c' <<'END_OF_FILE'
/* macPCstr.c -- niftyapp library pascal/C combination strings
*
* (C) Copyright 1990, 1991 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.
*
* Author: Christopher J. Newman
* Message: This is a nifty program.
*

* Created 9/1/88, Assembly Code 6/27/90
*/

#ifdef THINK_C
typedef unsigned char PCstr;

/* assembler function prototypes */
void PtoPCstrcpy(void);
void CtoPCstrcpy(void);
void PCtoPCstrcpy(void);
void PtoPCstrncpy(void);
void CtoPCstrncpy(void);
void PtoPCstrcat(void);
void CtoPCstrcat(void);
PCstr *PtoPCstr(void);
PCstr *CtoPCstr(void);
void SetPlen(void);
PCstr *longtoPCstr(long); /* not in assembler */

void PtoPCstrcpy( /* PCstr *dest, *src */ )
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
clr.w d0
move.b (a0),d0
clr.b 1(a1,d0)
@loop:
move.b (a0)+,(a1)+
dbf.w d0,@loop
}
}

void CtoPCstrcpy( /* PCstr *dest, char *src */)
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
addq.l #1,a1
moveq.l #-1,d0
@loop:
addq.w #1,d0
move.b (a0)+,(a1)+
bne.s @loop
movea.l 4(sp),a1 ; a1 = dest
move.b d0,(a1)
}
}

void PCtoPCstrcpy( /* PCstr *dest, PCstr *src */)
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
move.b (a0)+,(a1)+
@loop:
move.b (a0)+,(a1)+
bne.s @loop
}
}

void PtoPCstrncpy( /* PCstr *dest, char *src, short n */)
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
move.w 12(sp),d0 ; d0 = n
clr.w d1
move.b (a0)+,d1
cmp.w d0,d1
bcc.s @skip
move.w d1,d0
@skip:
move.b d0,(a1)+
subq.w #1,d0
bcs.s @exit
@loop:
move.b (a0)+,(a1)+
dbf d0,@loop
@exit:
}
}

void CtoPCstrncpy( /* PCstr *dest, char *src, short n */ )
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
addq.l #1,a1
clr.w d1
move.w 12(sp),d0 ; d0 = n
bra.s @skip
@loop:
addq.w #1,d1
move.b (a0)+,(a1)+
@skip:
dbeq.w d0,@loop
clr.b (a1)
movea.l 4(sp),a1 ; a1 = dest
move.b d1,(a1)
}
}

void PtoPCstrcat( /* PCstr *dest, char *src */ )
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
clr.w d0
clr.w d1
move.b (a0)+,d0
move.b (a1),d1
add.b d0,(a1)
lea.l 1(a1,d1),a1
bra.s @skip
@loop:
move.b (a0)+,(a1)+
@skip:
dbf.w d0,@loop
clr.b (a1)
}
}

void CtoPCstrcat( /* PCstr *dest, char *src */ )
{
asm 68000 {
movea.l 8(sp),a0 ; a0 = src
movea.l 4(sp),a1 ; a1 = dest
clr.w d0
move.b (a1),d0
lea.l 1(a1,d0),a1
subq.w #1,d0
@loop:
addq.w #1,d0
move.b (a0)+,(a1)+
bne.s @loop
movea.l 4(sp),a1 ; a1 = dest
move.b d0,(a1)
}
}

PCstr *PtoPCstr( /* char *str */ )
{
asm 68000 {
movea.l 4(sp),a0 ; a0 = str
clr.w d0
move.b (a0),d0
clr.b 1(a0,d0)
move.l a0,d0
}
}

PCstr *CtoPCstr( /* char *str */)
{
asm 68000 {
movea.l 4(sp),a0 ; a0 = str
move.b (a0)+,d0
lea.l (a0),a1
@loop:
move.b (a1),d1
move.b d0,(a1)+
move.b d1,d0
bne.s @loop
move.b d0,(a1)
suba.l a0,a1
move.l a1,d0
move.b d0,-(a0)
move.l a0,d0
}
}

void SetPlen( /* PCstr *pcstr */ )
{
asm 68000 {
movea.l 4(sp),a0 ; a0 = str
lea.l 1(a0),a1
moveq.l #-1,d0
@loop:
addq.w #1,d0
@skip:
tst.b (a1)+
bne.s @loop
move.b d0,(a0)
}
}
#else
/* C function prototypes in mac_napp.h */
#include "macnapp.h"

void PtoPCstrcpy(dest, src)
register PCstr *dest;
register char *src;
{
register short i;

i = Pstrlen(src);
C(dest)[i] = '\0';
do {
*dest++ = *src++;
} while (i--);
}

void CtoPCstrcpy(dest, src)
register PCstr *dest;
register char *src;
{
register short i;
register char *cpy;

cpy = C(dest);
for (i = 0; *cpy++ = *src++; i++);
*dest = i;
}

void PCtoPCstrcpy(dest, src)
register PCstr *dest;
register PCstr *src;
{
*dest++ = *src++;
while (*dest++ = *src++);
}

void PtoPCstrncpy(PCstr *dest, char *src, short n)
{
if (Pstrlen(src) < n) n = Pstrlen(src);
*dest++ = n;
src++;
while (n--) *dest++ = *src++;
*dest++ = '\0';
}

void CtoPCstrncpy(PCstr *dest, char *src, short n)
{
register char *tmp;
register short i;

tmp = C(dest);
for (i = 0; n-- && (*tmp++ = *src++); i++);
*tmp = '\0';
*dest = i;
}

void PtoPCstrcat(dest, src)
register PCstr *dest;
register char *src;
{
register short i;
register short j;

i = *dest;
*dest += (j = (unsigned char) *src++);
dest += i + 1;
while (j--) *dest++ = *src++;
*dest = '\0';
}

void CtoPCstrcat(dest, src)
register PCstr *dest;
register char *src;
{
register short i;
register char *tmp;

tmp = (char *) dest + (i = *dest) + 1;
while (*tmp++ = *src++) i++;
*dest = i;
}

PCstr *PtoPCstr(str)
register char *str;
{
SetClen((PCstr*) str);

return ((PCstr*) str);
}

PCstr *CtoPCstr(str)
register char *str;
{
register PCstr i;
register char c, d;
register char *tmp;

i = 0;
tmp = str;
tmp++;
c = *tmp++;
do {
d = *tmp;
*tmp++ = c;
i++;
} while (c = d);
(*(PCstr*)str) = i;

return ((PCstr*) str);
}

void SetPlen(pcstr)
register PCstr *pcstr;
{
register short i = -1;
register char *len = C(pcstr);

do {
i++;
} while (*len++);

*pcstr = i;
}
#endif

/* simple procedure to convert decimal number of
* less than 20 digits to a PC string.
* Compiling with 68020 option makes this quite a bit more efficient.
*/
PCstr *longtoPCstr(i)
register long i;
{
static PCstr sbuf[21];
register Boolean negflag;
register unsigned long val, ten = 10;
register PCstr *pos = sbuf + sizeof (sbuf) - 1;
register PCstr *posst;

*pos = '\0';
posst = --pos;
negflag = false;
val = i;
if (i < 0) {
negflag = true;
val = -i;
}
do {
*pos = (unsigned short) (val % ten) + '0';
pos--;
} while (val /= ten);
if (negflag) {
*pos = '-';
pos--;
}
*pos = posst - pos;

return (pos);
}

END_OF_FILE
fi
if test -f 'mpack-1.0/unixos.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/unixos.c'\"
else
echo shar: Extracting \"'mpack-1.0/unixos.c'\" \(5331 bytes\)
cat >'mpack-1.0/unixos.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>
#include <ctype.h>

#include <string.h>
#include <errno.h>
#include <sys/types.h>

#include <sys/param.h>
#include "xmalloc.h"
#include "common.h"

extern int errno;
extern char *malloc();
extern char *getenv();

int overwrite_files = 0;

/* The name of the file we're writing */
static char *output_fname = 0;

/* Characters that shouldn't be in filenames */
#define BADCHARS "!$&*()|\'\";<>[]{}?/`\\ \t"

/* Generate a message-id */
char *os_genid()
{

static int pid = 0;
static time_t curtime;
static char hostname[MAXHOSTNAMELEN+1];
char *result;

if (pid == 0) {
pid = getpid();
time(&curtime);
gethostname(hostname, sizeof(hostname));
}

result = malloc(25+strlen(hostname));
sprintf(result, "%d.%d@%s", pid, curtime++, hostname);
return result;
}

/* Create and return directory for a message-id */
char *os_idtodir(id)
char *id;
{

static char buf[4096];
char *p;

if (getenv("TMPDIR")) {
strcpy(buf, getenv("TMPDIR"));
}
else {
strcpy(buf, "/tmp");
}
strcat(buf, "/message-parts-");
strcat(buf, getenv("USER"));

(void)mkdir(buf, 0700);

p = buf + strlen(buf);

*p++ = '/';
while (*id) {
if (isprint(*id) && !strchr(BADCHARS, *id)) *p++ = *id;
id++;
}
*p = '\0';
if (mkdir(buf, 0700) == -1 && errno != EEXIST) {
perror(buf);
return 0;
}
*p++ = '/';


*p = '\0';
return buf;
}

/*


* We are done with the directory returned by os_idtodir()
* Remove it
*/
os_donewithdir(dir)
char *dir;
{

char *p;

/* Remove trailing slash */
p = dir + strlen(dir) - 1;
*p = '\0';

rmdir(dir);
}

/*


* Create a new file, with suggested filename "fname".
* "fname" may have come from an insecure source, so clean it up first.
* It may also be null.
* "contentType" is passed in for use by systems that have typed filesystems.
* "binary" is nonzero if the new file should be opened in binary mode.
*/
FILE *os_newtypedfile(fname, contentType, binary)
char *fname;
char *contentType;
int binary;
{
char *p;
static int filesuffix=0;
char buf[128], *descfname=0;
FILE *outfile = 0;

if (!fname) fname = "";

/* If absolute path name, chop to tail */
if (*fname == '/') {
p = strrchr(fname, '/');
fname = p+1;
}

/* Get rid of leading ~ or ~/ */
while (*fname == '~' || *fname == '/') fname++;

/* Clean out bad characters, create directories along path */
for (p=fname; *p; p++) {
if (*p == '/') {
if (!strncmp(p, "/../", 4)) {


p[1] = p[2] = 'X';
}

*p = '\0';
(void) mkdir(fname, 0777);
*p = '/';
}
else if (!isprint(*p) || strchr(BADCHARS, *p)) *p = 'X';
}

if (!fname[0]) {
do {
if (outfile) fclose(outfile);
sprintf(buf, "part%d", ++filesuffix);
} while (outfile = fopen(buf, "r"));
fname = buf;
}

else if (!overwrite_files && (outfile = fopen(fname, "r"))) {

do {
fclose(outfile);
sprintf(buf, "%s.%d", fname, ++filesuffix);

} while (outfile = fopen(buf, "r"));
fname = buf;
}

outfile = fopen(fname, "w");
if (!outfile) {
perror(fname);
}

if (output_fname) free(output_fname);
output_fname = strsave(fname);

if (strlen(fname) > sizeof(buf)-6) {
descfname = xmalloc(strlen(fname)+6);
}
else {
descfname = buf;
}
strcpy(descfname, fname);

p = strchr(descfname, '/');


if (!p) p = descfname;

if (p = strrchr(p, '.')) *p = '\0';

strcat(descfname, ".desc");
(void) rename(TEMPFILENAME, descfname);
if (descfname != buf) free(descfname);

fprintf(stdout, "%s (%s)\n", output_fname, contentType);

return outfile;
}

/*
* Warn user that the MD5 digest of the last file created by os_newtypedfile()
* did not match that supplied in the Content-MD5: header.
*/
os_warnMD5mismatch()
{
char *warning;

warning = xmalloc(strlen(output_fname) + 100);
sprintf(warning, "%s was corrupted in transit",
output_fname);
warn(warning);
free(warning);
}

/*


* Report an error (in errno) concerning a filename
*/
os_perror(file)
char *file;
{
perror(file);
}

END_OF_FILE
fi
if test -f 'mpack-1.0/unixpk.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/unixpk.c'\"
else
echo shar: Extracting \"'mpack-1.0/unixpk.c'\" \(6526 bytes\)
cat >'mpack-1.0/unixpk.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>
#include <string.h>

#include <errno.h>
#include "common.h"
#include "version.h"
#include "xmalloc.h"

#define MAXADDRESS 100

extern char *getenv();

extern int errno;


extern int optind;
extern char *optarg;

main(argc, argv)


int argc;
char **argv;
{
int opt;

char *fname = 0;
char *subject = 0;
char *descfname = 0;
long maxsize = 60000;
char *outfname = 0;

char *newsgroups = 0;


char *ctype = 0;
char *headers = 0;
int i;
char *p;
char sbuf[1024];
char fnamebuf[4096];
int part;
FILE *infile;

if ((p = getenv("SPLITSIZE")) && *p >= '0' && *p <= '9') {
maxsize = atoi(p);
}

while ((opt = getopt(argc, argv, "s:d:m:c:o:n:")) != EOF) {
switch (opt) {


case 's':
subject = optarg;
break;

case 'd':
descfname = optarg;
break;

case 'm':
maxsize = atoi(optarg);
break;

case 'c':
ctype = optarg;
break;

case 'o':
outfname = optarg;
break;

case 'n':
newsgroups = optarg;
break;

default:
usage();

}
}

if (ctype) {
if (!cistrncmp(ctype, "text/")) {
fprintf(stderr, "This program is not appropriate for encoding textual data\n");
exit(1);
}
if (cistrncmp(ctype, "application/", 12) && cistrncmp(ctype, "audio/", 6) &&
cistrncmp(ctype, "image/", 6) && cistrncmp(ctype, "video/", 6)) {
fprintf(stderr, "Content type must be subtype of application, audio, image, or video\n");
exit(1);
}
}

if (optind == argc) {


fprintf(stderr, "An input file must be specified\n");
usage();
}
fname = argv[optind++];

/* Must have exactly one of -o, -n, or destination addrs */
if (optind == argc) {
if (outfname && newsgroups) {
fprintf(stderr, "The -o and -n switches are mutually exclusive.\n");
usage();
}
if (!outfname && !newsgroups) {
fprintf(stderr, "Either an address or one of the -o or -n switches is required\n");
usage();
}
if (newsgroups) {
headers = xmalloc(strlen(newsgroups) + 25);
sprintf(headers, "Newsgroups: %s\n", newsgroups);
}
}
else {
if (outfname) {
fprintf(stderr, "The -o switch and addresses are mutually exclusive.\n");
usage();
}
if (newsgroups) {
fprintf(stderr, "The -n switch and addresses are mutually exclusive.\n");
usage();
}
headers = xmalloc(strlen(argv[optind]) + 25);
sprintf(headers, "To: %s", argv[optind]);
for (i = optind+1; i < argc; i++) {
headers = xrealloc(headers, strlen(headers)+strlen(argv[i]) + 25);
strcat(headers, ",\n\t");
strcat(headers, argv[i]);
}
strcat(headers, "\n");
}

if (!subject) {
fputs("Subject: ", stdout);
fflush(stdout);
if (!fgets(sbuf, sizeof(sbuf), stdin)) {
fprintf(stderr, "A subject is required\n");
usage();
}
if (p = strchr(sbuf, '\n')) *p = '\0';
subject = sbuf;
}

if (!outfname) {
if (getenv("TMPDIR")) {
strcpy(fnamebuf, getenv("TMPDIR"));
}
else {
strcpy(fnamebuf, "/tmp");
}
strcat(fnamebuf, "/mpackXXXXXX");
mktemp(fnamebuf);
outfname = strsave(fnamebuf);
}

if (encode(fname, descfname, subject, headers, maxsize, ctype, outfname)) exit(1);

if (optind < argc || newsgroups) {
for (part = 0;;part++) {
sprintf(fnamebuf, "%s.%02d", outfname, part);
infile = fopen(part ? fnamebuf : outfname, "r");
if (!infile) {
if (part) break;
continue;
}
if (newsgroups) {
inews(infile, newsgroups);
}
else {
sendmail(infile, argv, optind);
}
fclose(infile);
remove(part ? fnamebuf : outfname);
}
}

exit(0);
}

usage()
{
fprintf(stderr, "mpack version %s\n", MPACK_VERSION);
fprintf(stderr,
"usage: mpack [-s subj] [-d file] [-m maxsize] [-c content-type] file address...\n");
fprintf(stderr,
" mpack [-s subj] [-d file] [-m maxsize] [-c content-type] -o file file\n");
fprintf(stderr,
" mpack [-s subj] [-d file] [-m maxsize] [-c content-type] -n groups file\n");
exit(1);
}

sendmail(infile, addr, start)
FILE *infile;
char **addr;
int start;
{
int status;
int pid, i = 0, j = 0;

if (start < 2) abort();

#ifdef SCO
addr[--start] = "execmail";
#else
addr[--start] = "-oi";
addr[--start] = "sendmail";
#endif

do {
pid = fork();
} while (pid == -1 && errno == EAGAIN);

if (pid == -1) {
perror("fork");
return;
}
if (pid != 0) {
while (pid != wait(&status));
return;
}

dup2(fileno(infile), 0);
fclose(infile);
#ifdef SCO
execv("/usr/lib/mail/execmail", addr+start);
#else
execv("/usr/lib/sendmail", addr+start);
#endif
perror("execv");
_exit(1);
}

inews(infile)
FILE *infile;
{
int status;
int pid;

do {
pid = fork();
} while (pid == -1 && errno == EAGAIN);

if (pid == -1) {
perror("fork");
return;
}
if (pid != 0) {
while (pid != wait(&status));
return;
}

dup2(fileno(infile), 0);
fclose(infile);
execlp("inews", "inews", "-h", "-S", (char *)0);
execl("/usr/local/news/inews", "inews", "-h", "-S", (char *)0);
execl("/etc/inews", "inews", "-h", "-S", (char *)0);
execl("/usr/etc/inews", "inews", "-h", "-S", (char *)0);
execl("/usr/news/inews", "inews", "-h", "-S", (char *)0);
perror("execl");
_exit(1);
}

warn()
{
abort();
}
END_OF_FILE
fi
if test -f 'mpack-1.0/getopt.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/getopt.c'\"
else
echo shar: Extracting \"'mpack-1.0/getopt.c'\" \(2780 bytes\)
cat >'mpack-1.0/getopt.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#define ERR(s, c) \
if (opterr) { \
char buff[2]; \
buff[0] = c; buff[1] = '\n'; \
(void)write(2, av[0], strlen(av[0])); \
(void)write(2, s, strlen(s)); \
(void)write(2, buff, 2); \
}


int opterr = 1;
int optind = 1;
int optopt;
char *optarg;


/*
** Return options and their values from the command line.
** This comes from the AT&T public-domain getopt published in mod.sources
** (i.e., comp.sources.unix before the great Usenet renaming).
*/
int
getopt(ac, av, opts)
int ac;
char *av[];
char *opts;
{
extern char *strchr();
static int i = 1;
char *p;

/* Move to next value from argv? */
if (i == 1) {
if (optind >= ac ||
#ifdef __MSDOS__
(av[optind][0] != '-' && av[optind][0] != '/')
#else
av[optind][0] != '-'
#endif
|| av[optind][1] == '\0')
return EOF;
if (strcmp(av[optind], "--") == 0) {
optind++;
return EOF;
}
}

/* Get next option character. */
if ((optopt = av[optind][i]) == ':'
|| (p = strchr(opts, optopt)) == NULL) {
ERR(": illegal option -- ", optopt);
if (av[optind][++i] == '\0') {
optind++;
i = 1;
}
return '?';
}

/* Snarf argument? */
if (*++p == ':') {
if (av[optind][i + 1] != '\0')
optarg = &av[optind++][i + 1];
else {
if (++optind >= ac) {
ERR(": option requires an argument -- ", optopt);
i = 1;
return '?';
}
optarg = av[optind++];
}
i = 1;
}
else {
if (av[optind][++i] == '\0') {
i = 1;
optind++;
}
optarg = NULL;
}

return optopt;
}
END_OF_FILE
fi
if test -f 'mpack-1.0/magic.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/magic.c'\"
else
echo shar: Extracting \"'mpack-1.0/magic.c'\" \(2594 bytes\)
cat >'mpack-1.0/magic.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

/* Description of the various file formats and their magic numbers */
struct magic {
char *name; /* Name of the file format */
char *num; /* The magic number */
int len; /* Length of same (0 means strlen(magicnum)) */
};

/* The magic numbers of the file formats we know about */
static struct magic magic[] = {
{ "image/gif", "GIF", 0 },
{ "image/jpeg", "\377\330\377", 0 },
{ "video/mpeg", "\0\0\001\263", 4 },
{ "application/postscript", "%!", 0 },
};
static int num_magic = (sizeof(magic)/sizeof(magic[0]));
static char *default_type = "application/octet-stream";

/* The longest magic number */
static int max_magiclen = 0;

/*
* Determins the format of the file "inputf". The name
* of the file format (or NULL on error) is returned.
*/
char *magic_look(infile)
FILE *infile;
{
int i, j;
char buf[80];
int numread = 0;

if (max_magiclen == 0) {
for (i=0; i<num_magic; i++) {
if (magic[i].len == 0) magic[i].len = strlen(magic[i].num);
if (magic[i].len > max_magiclen) max_magiclen = magic[i].len;
}
}

numread = fread(buf, 1, max_magiclen, infile);
rewind(infile);

for (i=0; i<num_magic; i++) {
if (numread >= magic[i].len) {
for (j=0; j<magic[i].len; j++) {
if (buf[j] != magic[i].num[j]) break;
}
if (j == magic[i].len) return magic[i].name;
}
}

return default_type;
}
END_OF_FILE
fi
if test -f 'mpack-1.0/md5.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/md5.h'\"
else
echo shar: Extracting \"'mpack-1.0/md5.h'\" \(2132 bytes\)
cat >'mpack-1.0/md5.h' <<'END_OF_FILE'
/* MD5.H - header file for MD5C.C
*/

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.

License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.

License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.

RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/

/* GLOBAL.H - RSAREF types and constants
*/

/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif

/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;

/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;

/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;

/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif

/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;

void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, unsigned char *, unsigned int));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));

END_OF_FILE
fi
if test -f 'mpack-1.0/string.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/string.c'\"
else
echo shar: Extracting \"'mpack-1.0/string.c'\" \(2874 bytes\)
cat >'mpack-1.0/string.c' <<'END_OF_FILE'
/*
* String manipulation routines
*/


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/

#include <ctype.h>

static char upcase[256] = {


0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,

16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
' ','!','"','#','$','%','&', 39,'(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','[', 92,']','^','_',
'`','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','{','|','}','~',127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};

#define UPC(x) (upcase[(unsigned char)(x)])

/*
* Same as strcmp, but case-insensitive.
*/
int
cistrcmp(s1,s2)
register char *s1,*s2;
{
register char c1;
while ((c1 = *s1) && UPC(c1) == UPC(*s2)) {
s1++;
s2++;
}
return UPC(c1) - UPC(*s2);
}

/*
* Same as strncmp, but case-insensitive.
*/
int
cistrncmp(s1,s2,n)
register char *s1,*s2;
int n;
{
register char c1;
while (n-- && (c1 = *s1) && UPC(c1) == UPC(*s2)) {
s1++;
s2++;
}
if (n == -1) return 0;
return UPC(c1) - UPC(*s2);
}

END_OF_FILE
fi
if test -f 'mpack-1.0/unixpk.man' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/unixpk.man'\"
else
echo shar: Extracting \"'mpack-1.0/unixpk.man'\" \(2229 bytes\)
cat >'mpack-1.0/unixpk.man' <<'END_OF_FILE'
.TH MPACK 1
.SH NAME
mpack \- pack a file in MIME format
.SH SYNOPSIS
.B mpack
[
.B \-s
.I subject
]
[
.B \-d
.I descriptionfile
]
[
.B \-m
.I maxsize
]
[
.B \-c
.I content-type
]
.I file
.I "address \&..."
.br
.B mpack
[
.B \-s
.I subject
]
[
.B \-d
.I descriptionfile
]
[
.B \-m
.I maxsize
]
[
.B \-c
.I content-type
]
.B \-o
.I outputfile
.I file
.br
.B mpack
[
.B \-s
.I subject
]
[
.B \-d
.I descriptionfile
]
[
.B \-m
.I maxsize
]
[
.B \-c
.I content-type
]
.B \-n
.I newsgroups
.I file
.SH DESCRIPTION
The
.I mpack
program encodes the
the named file in one or more MIME messages.
The resulting messages are mailed to one or more recipients,
written to a named file or set of files, or posted to a set of
newsgroups.
.PP
.SH OPTIONS
.TP
.BI \-s " subject"
Set the
.B Subject
header field to
.IR Subject .
By default,
.B mpack


will prompt for the contents of the subject header.

.TP
.BI \-d " descriptionfile


Include the contents of the file

.I descriptionfile


in an introductory section at the beginning of the first
generated message.

.TP
.BI \-m " maxsize"


Split the message (if necessary) into partial messages, each not
exceeding

.I maxsize


characters. The default limit is the value of the

.B SPLITSIZE


environment variable, or 60000 characters if the environment variable
does not exist.
Specifying a

.I maxsize


of 0 means there is no limit to the size of the generated message.

.TP
.BI \-c " content-type"


Label the included file as being of MIME type

.IR content-type ,


which must be a subtype of

.BR application ,
.BR audio ,
.BR image ,
or
.BR video .


If this switch is not given,

.B mpack


examines the file to determine its type.

.TP
.BI \-o " outputfile"


Write the generated message to the file

.IR outputfile .


If the message has to be split, the partial messages will instead be
written to the files

.IR outputfile .01,
.IR outputfile .02,
etc.
.TP
.BI \-n " newsgroups"
Post the generated message(s) to the comma-separated netnews
.IR newsgroups .
.TP
.I file
Encode the named
.IR file .
.TP
.I "address \&..."
Mail the generated messages to the specified addresses.


.SH ENVIRONMENT
.TP
.B TMPDIR

Directory to store temporary files. Default is /tmp.
.TP
.B SPLITSIZE


Default value of the -m switch.

END_OF_FILE
fi
if test -f 'mpack-1.0/unixunpk.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/unixunpk.c'\"
else
echo shar: Extracting \"'mpack-1.0/unixunpk.c'\" \(2194 bytes\)
cat >'mpack-1.0/unixunpk.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

#include "version.h"

extern int optind;
extern char *optarg;

extern int overwrite_files;

main(argc, argv)
int argc;
char **argv;
{
int opt;
FILE *file;

while ((opt = getopt(argc, argv, "fC:")) != EOF) {
switch (opt) {
case 'f':
overwrite_files = 1;
break;

case 'C':
if (chdir(optarg)) {
perror(optarg);
exit(1);
}
break;

default:
usage();
}
}

if (optind == argc) {
fprintf(stderr, "munpack: reading from standard input\n");
handleMessage(stdin, "text/plain", 0);
exit(0);
}

while (argv[optind]) {
file = fopen(argv[optind], "r");
if (!file) {
perror(argv[optind]);


}
else {
handleMessage(file, "text/plain", 0);
fclose(file);
}

optind++;
}
exit(0);
}

usage() {


fprintf(stderr, "munpack version %s\n", MPACK_VERSION);
fprintf(stderr, "usage: munpack [-C directory] [files...]\n");
exit(1);
}

warn(s)
char *s;
{
fprintf(stderr, "munpack: warning: %s\n", s);
}
END_OF_FILE
fi

if test -f 'mpack-1.0/macmpack.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/macmpack.h'\"
else
echo shar: Extracting \"'mpack-1.0/macmpack.h'\" \(1974 bytes\)
cat >'mpack-1.0/macmpack.h' <<'END_OF_FILE'
/* mac_mpack.h -- resources for mac interface to mpack
*
* (C) Copyright 1993 by Christopher J. Newman


* 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 Christopher J. Newman not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Christopher J. Newman makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
* SHALL CHRISTOPHER J. NEWMAN 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.

*/

#define aboutDLOG 128
#define decodeDLOG 129
#define encodeDLOG 130
#define warnALRT 131
#define replaceALRT 132
#define errorALRT 133
#define mainMBAR 128

#define textWIND 128
#define helpWIND 129

#define helpTEXT 128
#define helpSTYL 128

/* apple menu */
#define iAbout 1
#define iHelp 2

/* file menu */
#define iEncode 1
#define iDecode 2
#define iOpen 4
#define iClose 5
#define iQuit 7

/* edit menu */
#define iSelectAll 7

/* decode dialog items */
#define iAdd 3
#define iRemove 4
#define iFileList 5
#define iFileScroll 6

/* encode dialog items */
#define iDescfile 11
#define iSubject 10
#define iMaximum 9

/* replace alert */
#define iNewname 1
#define iReplace 2
END_OF_FILE
fi
if test -f 'mpack-1.0/xmalloc.c' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/xmalloc.c'\"
else
echo shar: Extracting \"'mpack-1.0/xmalloc.c'\" \(1830 bytes\)
cat >'mpack-1.0/xmalloc.c' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/
#include <stdio.h>

extern char *malloc(), *realloc();

char *xmalloc (size)
int size;
{
char *ret;

if (ret = malloc((unsigned) size))
return ret;

fprintf(stderr, "Virtual memory exhausted\n");
exit(1);
}


char *xrealloc (ptr, size)
char *ptr;
int size;
{
char *ret;

/* xrealloc (NULL, size) behaves like xmalloc (size), as in ANSI C */
if (ret = !ptr ? malloc ((unsigned) size) : realloc (ptr, (unsigned) size))
return ret;

fprintf(stderr, "Virtual memory exhausted\n");
exit(1);
}

char *strsave(str)
char *str;


{
char *p = xmalloc(strlen(str)+1);
strcpy(p, str);
return p;
}

END_OF_FILE
fi
if test -f 'mpack-1.0/common.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/common.h'\"
else
echo shar: Extracting \"'mpack-1.0/common.h'\" \(1267 bytes\)
cat >'mpack-1.0/common.h' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/

#define TEMPFILENAME "tempdesc.txt"

#ifdef unix
#define remove unlink
#endif
END_OF_FILE
fi
if test -f 'mpack-1.0/version.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/version.h'\"
else
echo shar: Extracting \"'mpack-1.0/version.h'\" \(1216 bytes\)
cat >'mpack-1.0/version.h' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/

#define MPACK_VERSION "1.0"
END_OF_FILE
fi
if test -f 'mpack-1.0/xmalloc.h' -a "${1}" != "-c" ; then
echo shar: Not clobbering existing file \"'mpack-1.0/xmalloc.h'\"
else
echo shar: Extracting \"'mpack-1.0/xmalloc.h'\" \(1261 bytes\)
cat >'mpack-1.0/xmalloc.h' <<'END_OF_FILE'


/* (C) Copyright 1993 by John G. Myers
* 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 John G.
* Myers not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. John G. Myers makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL JOHN G. MYERS 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.
*/

extern char *xmalloc();
extern char *xrealloc();
extern char *strsave();
END_OF_FILE
fi
echo 'End of part 6 (of 6).'
echo 06 >> _shar_private

0 new messages