[comp.sources.amiga] v90i052: uucp 1.03D - unix compatible uucp/mail/news system, Part08/16

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/04/90)

Submitted-by: overload!dillon (Matt Dillon)
Posting-number: Volume 90, Issue 052
Archive-name: unix/uucp-1.03d/part08

#!/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", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 8 (of 16)."
# Contents:  SlowSetup.DOC src/dmail/load_mail.c src/uucico/gio.c
# Wrapped by tadguy@xanth on Sat Feb  3 20:51:14 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'SlowSetup.DOC' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'SlowSetup.DOC'\"
else
echo shar: Extracting \"'SlowSetup.DOC'\" \(14853 characters\)
sed "s/^X//" >'SlowSetup.DOC' <<'END_OF_FILE'
X
X			    SLOWSETUP.DOC
X
X			    Matthew Dillon
X			    891 Regal Rd.
X			    Berkeley, Ca. 94708
X
X			    pacbell.PacBell.COM!sorinc!overload!dillon
X
X
X		    GETTING UUCP UP AND RUNNING FOR REAL
X
X
X    This UUCP distribution in general is not for the uninitiated.  That is,
X    it is not user friendly.  This particular document outlines a general
X    installation procedure.  Be warned that there are a LOT of things you
X    will have to do to bring up UUCP on your machine.
X
X    This document shows a TYPICAL setup.  You will most likely want to
X    modify the example to fit your own needs.  I cover all the points
X    though.
X
X    (1) You made backups of the distribution floppies, right?  DO NOT
X	MODIFY THE DISTRIBUTION FLOPPIES.  The instructions below are
X	long and some are complex and you may wish to refer to the
X	original distribution diskettes if you accidently mess something
X	up.
X
X
X    (2A) Installing UUCP on a single floppy system.
X
X	Well, it *is* possible, but difficult.	you need to make as much
X	space as possible available on the main floppy.
X
X	The second distribution disk contains only the source and manual
X	pages.	I suggest you shuffle things around a bit.  You already
X	have a copy of the first distribution diskette. I suggest you
X	format a new disk and put the MAN directory of the second
X	distribution disk on it.  Note that there is a MAN directory
X	on the boot disk as well but this one contains only dmail.help
X	which you need to gain online help from dmail.
X
X	The following executables are required on the boot floppy and
X	should not be moved off.  You should move as many of the remaining
X	executables somewhere else as you can.
X
X	    Required Executables in C
X
X	    c/dmail
X	    c/getty
X	    c/rmail
X	    c/uucico
X	    c/rnews
X	    c/uucp
X	    c/unbatcher
X	    c/dme	    (unless you configure your own editor)
X	    c/sendmail
X	    c/uux
X	    c/uuxqt
X
X	You will want to change the ASSIGNments in s/startup-sequence
X	as follows:
X
X	    Assign UUSPOOL:	UUCP:SPOOL
X	    Assign UUMAIL:	UUCP:MAIL
X	    Assign UUNEWS:	UUCP:MAIL/NEWS
X
X	These directories MUST be in nonvoltile storage or your USENET
X	node will be unreliable.
X
X    (2B) Installing UUCP on a duel floppy system.
X
X	In this case very little shuffling is required.  I suggest
X	the second floppy be used for UUSPOOL:, UULIB:, UUMAIL:, UUNEWS:,
X	GETTY:, and UUPUB:.
X
X	Format a new floppy (this will be your second floppy) and create
X	directories as follows:
X
X	    MakeDir df1:spool
X	    MakeDir df1:mail
X	    MakeDir df1:mail/news
X	    MakeDir df1:pub
X	    MakeDir df1:lib
X
X	Modify the Assignments in s/startup-sequence of the boot floppy
X	as follows:
X
X	    Assign UUSPOOL:	df1:spool
X	    Assign UULIB:	df1:lib
X	    Assign UUMAIL:	df1:mail
X	    Assign UUNEWS:	df1:mail/news
X	    Assign GETTY:	UULIB:
X	    Assign UUPUB:	df1:pub
X
X	Copy df0:lib to df1:lib and either delete or rename df0:lib to
X	prevent confusion.  What we have done is move all dynamic storage
X	to df1: .. files that will change a lot or require a lot of disk
X	space.	Specifically, UULIB: was moved to DF1: because the
X	sequence number file is kept in UULIB: and this is updated for
X	each mail message sent.
X
X    (2B) Installing UUCP on a Hard Drive
X
X	Make a directory called UUCP on your hard drive somewhere.  And
X	Assign UUCP: to it.   Copy the contents of both distribution
X	floppies to your harddrive:
X
X	    (put first disk in DF0:)
X	    1> Copy df0: UUCP: ALL CLONE
X	    (put second disk in DF0:)
X	    1> Copy df0: UUCP: ALL CLONE
X
X	It is easiest to keep all the directories in one place.  Note
X	that a MAN directory exists on both distribution floppies, simply
X	merge them together.
X
X	Merge the startup-sequence on the boot floppy into your master
X	startup-sequence.  Make sure you get all the Assigns and that
X	they are properly reassigned to the appropriate directory on
X	the harddisk.  Most people normally make a master UUCP: assign
X	as a reference point to other assigns.
X
X
X	Be sure that UUSPOOL:, UUMAIL:, UUNEWS: and UUPUB: are assigned
X	to your hard disk instead of ram.
X
X	You will most likely want to run DCron and Getty from your
X	startup-sequence.  Be sure that UUCP:C is assigned *before*
X	these programs are run so they pick up the appropriate path.
X
X	If Getty interferes with any terminal program you might use
X	you may be forced to BREAK it.	Remember to restart it to
X	enable incomming UUCP calls again.
X
X	DCron is an extremely useful utility to run, especially in
X	systems with hard disks.  The only thing you have to watch out
X	for is to be sure to BREAK it (kill it) before shutting off your
X	machine.  DCron writes to its log file and runs other programs
X	based on the date and you don't want to accidently turn off your
X	machine when DCron has just started up some other program that
X	may write to your hard disk.
X
X	In the context of UUCP, DCron is normally used to automatically
X	poll systems in the wee hours while you are asleep, to trim
X	log files automagically, and maybe disable the modem's speaker
X	while you are asleep (at least, that is what I use it for).
X
X	Most people with HDs running UUCP leave their Amiga's on 24 hours
X	a day.
X
X			    Other System Directories
X
X	Merge the mountlist into your master mountlist and copy any
X	devices from l that you do not already have into your
X	master l directory.
X
X	merge or copy uucp:s/crontab to s:crontab and uucp:s/.edrc to
X	s:.edrc .
X
X	You can ignore files in uucp:system, they are standard system
X	files.
X
X		----	--  -	-   -	-   -	-  --	----
X
X    (3)     Other startup-sequence efficiency considerations
X
X	UUCP relies heavily on the Amiga's multitasking capabilities.
X	Most programs execute other programs.  Many programs in UUCP:C
X	may be made resident as shown by the pure bit being set.  You
X	will probably at least want to make C:RUN resident if you haven't
X	already.
X
X	Depending on available RAM you may want to make certain other
X	progams resident.  Here are some suggestions:
X
X		uucp:c/dme	    ; run by dmail to edit mail
X		uucp:c/uuxqt	    ; run by uucico to handle received files
X		uucp:c/rmail	    ; run by uuxqt to handle received mail
X		uucp:c/sendmail     ; run by dmail to handle outgoing mail
X
X		(note that uucp:c/sendmail and uucp:c/rmail are the same
X		 executable just renamed)
X
X	STACK:	All programs should run with a stack of 8192.  This
X	has been tested for all programs except RNews and ANews which
X	may require more.
X
X	RNEWS:	RNews currently takes a huge amount of memory and
X	will run only on machines with at least 1.5MB of ram.  Even
X	with 1.5MB you may need to run rnews manually instead of having
X	it automatically run by uuxqt.	In this case rename the rnews
X	executable to something else and create a dummy script file
X	in its place (named as 'rnews') with the script bit set.
X
X    (4)     System requirements
X
X	Be sure you are running at least version 1.3 of the operating
X	system.  The main consideration is that you are using at least
X	the 1.3 serial device.
X
X	The NULL: device is required, this is in the l directory of
X	the boot floppy as already discussed.
X
X	The UUSER: device is not required unless you want to start
X	getting fancy with the Getty.  This is mainly a programmer's
X	tool.
X
X    (5)     Getty
X
X	Normally one runs a Getty in his startup-sequence on the internal
X	serial port (from which you wish to receive calls).  Currently
X	only one Getty may be run PER SERIAL DEVICE NAME, and using other
X	units of a given serial device will interfere with Getty's operation.
X	This is due to the difficulty of implementation in Getty and will
X	eventually be fixed (to fix the problem I have to patch into
X	the OpenDevice and CloseDevice vectors).
X
X	So for now you can really only run Getty on the internal serial
X	device.
X
X	Getty does its best to not interfere with comm programs and
X	the like, but if a comm program refuses to run because it
X	can't get exclusive access to the serial port you may have
X	to kill the Getty by BREAKing it from a CLI.
X
X	Refer to the manual page MAN:Getty for more information (for
X	floppy based systems all manual pages are on the second
X	distribution diskette).
X
X    (6)     SHELL-STARTUP
X
X	Assuming you are using the 1.3 Shell, the S:Shell-Startup file
X	normally contains at least a Path command and Stack command to
X	properly setup a newshell's path and stack.  Be sure the stack is
X	at least 8192 for this distribution of UUCP and add the UUCP:C (or
X	wherever you have placed the distribution executables) to your path
X	list.  Older UUCP distributions required a huge stack, this has
X	been fixed.
X
X    (7)                   SITE-SETUP CONTROL FILES
X
X	The following is a description of control and log files required
X	for UUCP and how you must modify them to install your system.
X
X	(GETTY: is normally Assign'd to UULIB:)
X
X	GETTY:Getty-Header
X
X	    This file contains the header line that is printed before a
X	    login: prompt and is typically only two or three lines long.
X	    The header usually contains your node name and the version of
X	    the OS you are running under so people calling from term
X	    programs know who you are.
X
X	    (Getty can be used to run things other than uucico)
X
X	    Modify accordingly.
X
X	GETTY:Passwd
X
X	    The password file is used by Getty to authenticate login
X	    requests.  In the context of UUCP, remote UUCICOs that call
X	    your machine up will provide a login and password.	Getty
X	    handles this and if the login is valid and the password matches
X	    will run the appropriate program found in the password file.
X
X	    Getty also deals with such features as automatic disconnect on
X	    timeout and logs times for all incomming and outgoing calls.
X
X	    In a serious system you should first remove all the junk
X	    entries that come with the distribution.   You need an entry
X	    for each remote machine you want to be able to call you.  You
X	    do not necessarily need to give them logins that corrospond to
X	    their machine names though this is how it is usually done.
X
X	    Other programs in the future will be able to be run from
X	    a Getty.
X
X	    Later versions of UUCP will implement MAILER-DAEMON type
X	    stuff like 'unknown user', in which case the password file
X	    will be used to define which user names are valid on the
X	    system.
X
X	GETTY:LOGFILE
X
X	    The logfile is appended to by Getty whenever an incomming
X	    call occurs or somebody takes over the serial port.  It
X	    logs connect and disconnect times for incomming calls and
X	    usage for external programs.
X
X	UULIB:Domain
X
X	    In nearly every case you will not need this file.
X
X	    Those of you who wish to do domain routing through
X	    their machine or have more than one default for
X	    unknown destinations should refer to the manual
X	    page MAN:Domains.
X
X	UULIB:.Signature
X
X	    .Signature is used by the Mail program and normally appended
X	    to outgoing mail.
X
X	    Modify accordingly.
X
X	UULIB:Seq
X
X	    The Seq file should exist but otherwise not be modified by
X	    the user (except for setting it to a "1" once a year).  This
X	    file is atomically updated and used to provide unique filenames
X	    and mail IDs for outgoing mail.
X
X	UULIB:Security
X
X	    This file contains a list of allowed directories remote UUCP
X	    transfers may read and write to.  Refer to the Security manual
X	    page.  This file never contains the UUSPOOL: directory which
X	    is implicitly read-write.
X
X	    You need not modify this file now but should keep it in mind.
X	    It protects your system in as much as I have been able to
X	    close the loopholes.  Loopholes might still exist.
X
X	UULIB:news.distribution
X
X	    This file contains a list of news distribution idents for
X	    various areas and must normally be modified according to
X	    where you are.. you need to be a UUCP guru to do this.  Most
X	    people can just leave it alone.
X
X	UULIB:Config
X
X	    This file contains configuration information for many
X	    executables in UUCP:C and should be modified accordingly.
X
X	    Be sure you modify at least the following entries.	REFER TO
X	    THE 'Assigns' MANUAL PAGE.
X
X		NodeName
X		UserName
X		RealName
X		NewsFeed    (not required if you don't care about news)
X		Organization
X		TimeZone
X		DefaultNode
X
X	    **** Take some time to pick a node name for yourself.  It
X		 should be no more than 8 characters long.  Some UUCP sites
X		 barf at node names longer than 6 chars so if you are not
X		 sure of your neighbors pick one no more than 6 characters
X		 long.	Your site name should be in lower case.
X
X	UULIB:L.Sys
X
X	    This file contains site information for sites that may call
X	    you up or you may call up.
X
X	    You must modify this file appropriately before you can run UUCP,
X	    refer to the 'L.Sys' manual page.
X
X	UULIB:Aliases
X
X	    This is a mail aliases file with aproximately the same
X	    power as /usr/lib/aliases on UNIX systems.	You should
X	    refer to the 'Aliases' manual page and modify this file as
X	    appropriate for various defaults like 'postmaster'... to
X	    whatever user name you pick for yourself.
X
X	UUCP:S/Crontab
X
X	    This is a functional Crontab file for use with the DCron program.
X	    This file is normally moved to S: (it is useless in UUCP:S).
X
X	UUSPOOL:LOGFILE
X
X	    UUCICO and other programs log errors and other things to
X	    this file.	Normally you use DCron to clean up this and
X	    other log files once daily to keep them from getting to large.
X
X
X    (8)     TESTING / DMAIL
X
X	You will next want to test your UUCP configuration.  If testing
X	with a friend's Amiga running the same distribution simply
X	email to him, then one of you run uucico -s<remotesystem>
X	just like in QuickSetup.DOC, except this time you are using
X	the system name he picked instead of 'test1' or 'test2'.
X
X	If the initial tests in QuickSetup.DOC worked and the system
X	is not working now check the following (common problems):
X
X	    (a) the login and password in your L.Sys file (that uucico uses
X		to login to the remote machine) matches the login and
X		password in the remote machine's Getty:Passwd file.
X
X	    (b) There is an entry for your node in the remote machine's
X		L.Sys file and vise versa
X
X	    (c) The telephone number is correct
X
X	    (d) the node names are all in lower case
X
X	    (e) you constructed the email address correctly (nodename!user)
X
X	I suggest you get UUCP running with a friend before getting it
X	running with a UNIX system as it is easier to test it with a
X	friend.
X
X	Assuming you email to the user name he picked for his UULIB:Config
X	'UserName' entry and he did the same thing to you, entering
X	'dmail' without any arguments will bring up the mail shell
X	and allow you to read the message after transfer via UUCico
X	is complete.  You can check that the email actually arrived
X	into the right mail box in UUMAIL: by simply getting a directory
X	of UUMAIL:
X
X	READ the manual page for DMail for information on the
X	construction of mail paths to other systems and users.
X
X
END_OF_FILE
if test 14853 -ne `wc -c <'SlowSetup.DOC'`; then
    echo shar: \"'SlowSetup.DOC'\" unpacked with wrong size!
fi
# end of 'SlowSetup.DOC'
fi
if test -f 'src/dmail/load_mail.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/dmail/load_mail.c'\"
else
echo shar: Extracting \"'src/dmail/load_mail.c'\" \(13593 characters\)
sed "s/^X//" >'src/dmail/load_mail.c' <<'END_OF_FILE'
X
X/*
X *  LOAD_MAIL.C
X *
X *  (C) Copyright 1985-1990 by Matthew Dillon,  All Rights Reserved.
X *
X *  file-io routines to scan the mail file and load required information.
X *
X *
X *  Global Routines:	HOLD_LOAD()         hold on loading mail after change
X *			NOHOLD_LOAD()       hold off.. load if changes
X *			LOAD_CHANGES()      reload mail if changed
X *			LOAD_MAIL()         load/reload mail
X *			SAVE_FILE()         save mail items back to spool
X *			CHECK_NEW_MAIL()    check for new mail
X *			WRITE_FILE()        append mail items to a file
X *			GET_EXTRA_OVR()     ret index of Field (create if not)
X *			ADD_EXTRA()         add another field (reloads mail)
X *			DELETE_EXTRA()      delete a field
X *			GET_EXTRA()         ret index of Field, or error
X *			M_SELECT()          select on current message list
X *
X *
X *  Static Routines:	LOAD_HASH()         load hash table from fields list
X *			FREE_ENTRY()        unload EVERYTHING
X *			FREE_TABLE()        unload all Fields table
X *			LOAD_FILE()         raw file loading/counting
X *
X *
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X#include "dmail.h"
X
Xvoid do_flock();
Xvoid free_table();
Xvoid load_hash();
X
X#define NOHOLD	0
X#define HOLD	1
X
X#define NO_BASE     0
X#define NO_FIELDS   1
X#define ENTRY_OK    2
X
Xstruct FIND Find[MAXTYPE + 1] = {
X	"From:"   , 5, 1, 0,
X	"To:"     , 3, 1, 0,
X	"Subject:", 8, 1, 0 };
X
Xstatic int  File_size;
Xstatic int  changed, load_hold;
Xstatic int  Hash[256];
X
Xstatic char *quo_quo = "";
X
Xvoid
Xhold_load()
X{
X    load_hold = 1;
X}
X
Xvoid
Xnohold_load()
X{
X    void load_changes();
X    load_hold = 0;
X    load_changes();
X}
X
Xvoid
Xload_changes()
X{
X    if (changed  &&  !load_hold)
X	load_mail(Entries, 1);
X}
X
Xinitial_load_mail()
X{
X    if (load_mail (0, 0) < 0)
X	return (-1);
X    return ((Entries) ? 1 : -1);
X}
X
X
Xstatic
Xload_mail(at, from0)
X{
X    FILE *fi;
X    int i, count, file_size;
X
X    if (No_load_mail)
X	return (-1);
X    push_break();
X    load_hash();
X    if (from0)
X	free_table (0, HOLD);
X    else
X	free_table (at, NOHOLD);
X    fi = fopen (mail_file, "r+");
X    if (m_fi != NULL)
X	fclose (m_fi);
X    m_fi = fopen (mail_file, "r+");
X    if (fi == NULL  ||  m_fi == NULL) {
X	pop_break();
X	return (-1);
X    }
X    do_flock (fileno(m_fi), LOCK_EX);
X    if (at)
X	fseek (fi, Entry[at].fpos, 0);
X    else
X	fseek (fi, 0, 0);
X    count = Entries;
X    while (search_from(fi))
X	++count;
X    if (Entries != count) {
X	if (!lmessage_overide)
X	    printf ("%d Other Items loaded\n", count - Entries);
X	lmessage_overide = 0;
X	Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry) * (count + 1));
X	bzero (&Entry[Entries], sizeof(*Entry) * (count + 1 - Entries));
X    }
X    Entries = count;
X    for (i = at; i < Entries; ++i)
X	Entry[i].no  =	Entry[i].status = 0;
X    Entry[i].fpos = File_size = file_size = ftell (fi);
X    fclose (fi);
X    load_file ((from0) ? 0 : at);
X    if (file_size != File_size) {       /* Last entry incomplete?       */
X	free_table (Entries - 1, NOHOLD);
X    }
X    changed = 0;
X    flock (fileno(m_fi), LOCK_UN);
X    pop_break();
X    return (1);
X}
X
Xvoid
Xdo_flock(fd, stat)
X{
X    if (flock(fd, stat | LOCK_NB) < 0) {
X	puts ("File in use, Waiting for lock");
X	flock (fd, stat);
X	puts ("Have lock");
X    }
X}
X
Xstatic
Xload_file(at)
Xint at;
X{
X    FILE *fi;
X    char *next, *ptr;
X    int i, bit, maxbit, len, count, havefrom;
X
X    maxbit = 0;
X    for (i = 0; Find[i].search != NULL; ++i)
X	maxbit = (maxbit << 1) | 1;
X    fi = fopen (mail_file, "r");
X    count = -1;
X    havefrom = 0;
X    while (havefrom  ||  search_from (fi)) {
X	havefrom = 0;
X	if (++count >= Entries)
X	    break;
X	len = strlen(Buf) - 1;
X	Buf[len] = '\0';
X	next = next_word(Buf);
X	len -= next - Buf;
X	Entry[count].fpos = ftell (fi);
X	Entry[count].from = malloc (len + 1);
X	bcopy (next, Entry[count].from, len + 1);
X
X	/* SEARCH FIELD LIST */
X
X	bit = 0;
X	if (XDebug)
X	    printf ("No %d  ---------------------\n", count + 1);
X	while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
X	    if (Buf[0] == '\n')
X		break;
X	    if (isfrom(Buf)) {
X		havefrom = 1;
X		break;
X	    }
X	    len = strlen(Buf) - 1;
X	    Buf[len] = '\0';
X	    if (XDebug)
X		printf ("CHECK: %s\n", Buf);
X	    next = next_word(Buf);
X	    len -= next - Buf;
X	    if (Hash[*Buf] == 0)
X		continue;
X	    if (Hash[*Buf] > 0) {
X		i = Hash[*Buf] & 0xff;
X		if (strncmp (Find[i].search, Buf, Find[i].len) == 0)
X		    goto found;
X		continue;
X	    }
X	    for (i = -Hash[*Buf] & 0xff; Find[i].search; ++i) {
X		if (*Find[i].search != *Buf)
X		    break;
X		if (strncmp (Find[i].search, Buf, Find[i].len) == 0)
X		    goto found;
X	    }
X	    continue;
Xfound:
X	    if (XDebug)
X		printf ("Found: %d %s\n", i, Buf);
X	    if (Find[i].notnew == 0) {
X		Find[i].notnew = 1;
X		ptr = Buf;
X		while (*ptr  &&  *ptr != ':')
X		    ++ptr;
X		++ptr;
X		Find[i].search =
X			realloc (Find[i].search, ptr - Buf + 1);
X		strncpy (Find[i].search, Buf, ptr - Buf);
X		*(Find[i].search + (ptr - Buf)) = '\0';
X		Find[i].len = strlen(Find[i].search);
X	    }
X	    compile_field (Buf, fi);
X	    Entry[count].fields[i] =
X		    malloc (strlen(next) + 1);
X	    strcpy (Entry[count].fields[i], next);
X	    if ((bit |= (1 << i)) == maxbit)
X		break;
X	}
X	if (bit != maxbit) {
X	    for (i = 0; Find[i].search != NULL; ++i) {
X		if (((1 << i) & bit) == 0) {
X		    Entry[count].fields[i] = quo_quo;
X		}
X	    }
X	}
X    }
X    File_size = ftell (fi);
X    fclose (fi);
X    return (1);
X}
X
X
Xstatic void
Xload_hash()
X{
X    register int i, c;
X
X    bzero (Hash, sizeof(Hash));
X    for (i = 0; Find[i].search; ++i) {
X	c = *Find[i].search;
X	if (Hash[c] > 0)
X	    Hash[c] = -Hash[c];
X	if (Hash[c] == 0)
X	    Hash[c] = i | 0x100;
X    }
X}
X
X
Xvoid
Xfree_entry()
X{
X    free_table(0, NOHOLD);
X    Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry));
X    bzero (Entry[0].fields, sizeof(Entry[0].fields));
X    File_size = Entries = 0;
X    Entry->status = Entry->no = Entry->fpos = Current = 0;
X    Listsize = 3;
X    if (m_fi) {
X	fclose (m_fi);
X	m_fi = NULL;
X    }
X}
X
X
Xstatic void
Xfree_table(at, hold)
X{
X    int i, j;
X
X    for (i = at; i < Entries; ++i) {
X	xfree (Entry[i].from);
X	for (j = 0; Find[j].search != NULL; ++j) {
X	    if (Entry[i].fields[j] != quo_quo)
X		xfree (Entry[i].fields[j]);
X	}
X    }
X    Entries = (hold == HOLD) ? Entries : at;
X    File_size = (at) ? Entry[Entries].fpos : 0;
X}
X
Xstatic
Xsearch_from(fi)
XFILE *fi;
X{
X    while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
X	if (isfrom (Buf))
X	    return (1);
X    }
X    return (0);
X}
X
X
Xsave_file(reload, mark, notmark)
X{
X    FILE *fiscr;
X    int fdscr;
X    int new_size, i, count;
X    char scratch[64];
X
X    for (i = 0; i < Entries; ++i) {
X	if ((Entry[i].status & mark) != mark  ||
X		(~Entry[i].status & notmark) != notmark)
X	    break;
X    }
X    if (i == Entries) {
X	m_select (Nulav, M_RESET);
X	puts ("No Changes Made");
X	return (Entries);
X    }
X    if (m_fi == NULL)
X	return (-1);
X    count = 0;
X    sprintf (scratch, "tmp:dmail%d", getpid());
X    do_flock (fileno(m_fi), LOCK_EX);
X    fdscr = open (scratch, O_RDWR | O_CREAT | O_TRUNC, MAILMODE);
X#ifdef AMIGA	    /*	fix bug in Lattice C fdopen */
X    fiscr = fopen("nil:", "w");
X    fclose(fiscr);
X#endif
X    fiscr = fdopen (fdscr, "a+");
X    for (i = 0; i < Entries; ++i) {
X	if ((Entry[i].status & mark) == mark  &&
X		(~Entry[i].status & notmark) == notmark) {
X	    ++count;
X	    fputs ("From ", fiscr);
X	    fputs (Entry[i].from, fiscr);
X	    putc ('\n', fiscr);
X	    fseek (m_fi, Entry[i].fpos, 0);
X	    while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
X		if (isfrom(Buf))
X		    break;
X		fputs (Buf, fiscr);
X	    }
X	}
X    }
X
X    /* If NEW MAIL has come in, append that to the scratch file also */
X
X    new_size = (fseek (m_fi, 0, 2) >= 0) ? ftell(m_fi) : File_size;
X    if (File_size != new_size) {
X	fseek (m_fi, File_size, 0);
X	while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL)
X	    fputs (Buf, fiscr);
X    }
X
X    /* Write scratch file back to mail file, or try to */
X
X    fflush (fiscr);
X    fflush (m_fi);
X
X    lseek (fdscr, 0 ,0);
X#ifdef UNIX
X    lseek (fileno(m_fi), 0, 0);
X    while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
X	write (fileno(m_fi), Buf, i);
X    ftruncate (fileno(m_fi), lseek (fileno(m_fi), 0, 1));
X#else
X    fclose(m_fi);
X    if (m_fi = fopen (mail_file, "w")) {
X	while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
X	    write (fileno(m_fi), Buf, i);
X	fclose(m_fi);
X	m_fi = fopen (mail_file, "r+");
X    }
X    if (m_fi == NULL) {
X	printf("Unable to re-open %s !\n", mail_file);
X	return(-1);
X    }
X#endif
X    if (lseek (fileno(m_fi), 0, 2) == 0  &&  !reload) {
X	if (Did_cd == 0) {
X	    fclose(m_fi);
X	    m_fi = NULL;
X	    if (unlink (mail_file) == 0)
X		printf ("%s  Removed\n", mail_file);
X	    else
X		printf ("0 messages left in %s\n", mail_file);
X	}
X    }
X    fclose (fiscr);
X    if (m_fi)
X	fclose (m_fi);          /* Effectively unlocks the descriptor */
X    m_fi = NULL;
X    unlink (scratch);
X    if (reload) {
X	free_entry();
X	load_mail(0, 0);
X    }
X    m_select (Nulav, M_RESET);
X    return (count);
X}
X
Xvoid
Xcheck_new_mail()
X{
X    push_break();
X    if (m_fi == NULL) {
X	m_fi = fopen (mail_file, "r+");
X	if (m_fi == NULL) {
X	    pop_break();
X	    return;
X	}
X    }
X    if (fseek (m_fi, 0, 2) < 0 || ftell(m_fi) != File_size)
X	load_mail(Entries, 1);
X    pop_break();
X}
X
X
Xwrite_file(file, modes, mark, notmark)
Xchar *file;
X{
X    int i, fd = 1, notopen = 1;
X    FILE *fi = NULL;
X
X    for (i = 0; i < Entries; ++i) {
X	if ((Entry[i].status & mark) == mark  &&
X		(~Entry[i].status & notmark) == notmark) {
X	    if (notopen) {
X		notopen = 0;
X		fd = open (file, O_APPEND | O_WRONLY | modes, MAILMODE);
X		if (fd < 0)
X		    return (-1);
X		do_flock (fd, LOCK_EX);
X#ifdef AMIGA	    /*	fix bug in Lattice C fdopen */
X		fi = fopen("nil:", "w");
X		fclose(fi);
X#endif
X		fi = fdopen (fd, "a");
X
X#ifdef NOTDEF
X		if (fi) {
X		    printf("ptr     %08lx\n", fi->_ptr);
X		    printf("rcnt    %08lx\n", fi->_rcnt);
X		    printf("wcnt    %08lx\n", fi->_wcnt);
X		    printf("base    %08lx\n", fi->_base);
X		    printf("size    %08lx\n", fi->_size);
X		    printf("flag    %08lx\n", fi->_flag);
X		    printf("file    %08lx\n", fi->_file);
X		    return(-1);
X		}
X#endif
X	    }
X	    fputs ("From ", fi);
X	    fputs (Entry[i].from, fi);
X	    putc ('\n', fi);
X	    if (m_fi) {
X		fseek (m_fi, Entry[i].fpos, 0);
X		while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
X		    if (isfrom(Buf))
X			break;
X		    fputs (Buf, fi);
X		}
X	    }
X	}
X    }
X    if (!notopen)
X	fclose (fi);
X    return (1);
X}
X
X/*
X * Basic scheme: Each entry has a fields list.	Each entry in the fields list
X * is guarenteed to be a valid malloc'd pointer (except some may be set to
X * quo_quo).
X *
X * The find[] struct array holds the field name and length, the index
X * corresponding to the index into the field[] in an Entry.
X *
X * The header and width arrays hold the list format.
X */
X
Xget_extra_ovr(str)
Xchar *str;
X{
X    register int i;
X
X    i = get_extra (str);
X    if (i < 0) {
X	i = add_extra (str);
X	load_changes();
X    }
X    return (i);
X}
X
X
X/*
X * If there's room to add it, append to end.
X * Else Find oldest field which doesn't exist in the setlist and replace it
X *  with the new one.
X */
X
Xadd_extra(str)
Xchar *str;
X{
X    register int i, j, j_age, k;
X
X    for (i = EXSTART; i < MAXTYPE; ++i) {
X	if (Find[i].search == NULL)
X	    break;
X	++Find[i].age;
X    }
X    if (i == MAXTYPE) {                 /* No room to add onto end */
X	j = j_age = -1;
X	for (i = EXSTART; i < MAXTYPE; ++i) {
X	    for (k = 0; k < Listsize; ++k) {
X		if (i == header[k])
X		    break;
X	    }
X	    if (k == Listsize  &&  Find[i].age > j_age) {
X		j = i;
X		j_age = Find[i].age;
X	    }
X	}
X	i = j;
X    }
X    if (i < 0)
X	return (-1);
X    push_break();
X    if (Find[i].search != NULL)
X	xfree (Find[i].search);
X    Find[i].len = strlen(str);
X    Find[i].search = malloc (Find[i].len + 1);
X    Find[i].notnew = Find[i].age = 0;
X    strcpy (Find[i].search, str);
X    changed = 1;
X    for (j = 0; j < Entries; ++j) {
X	if (Entry[j].fields[i] && Entry[j].fields[i] != quo_quo)
X	    xfree (Entry[j].fields[i]);
X	Entry[j].fields[i] = quo_quo;
X    }
X    pop_break();
X    return (i);
X}
X
X
Xget_extra(str)
Xchar *str;
X{
X    int i;
X
X    for (i = 0; Find[i].search; ++i) {
X	if (strncmp (str, Find[i].search, strlen(str)) == 0) {
X	    Find[i].age = 0;
X	    return (i);
X	}
X    }
X    return (-1);
X}
X
X
Xm_select(sav, mode)
Xregister char *sav[];
X{
X    char *ptr, *dest;
X    char l_map[256];
X    int idx[MAXLIST], ix = 0;
X    int ok, not, len, scr;
X    register int i, j, avi;
X
X    for (i = 0;i < 256; ++i)
X	l_map[i] = i;
X    for (i = 'A'; i <= 'Z'; ++i)
X	l_map[i] += 'a' - 'A';
X    hold_load();
X    i = 0;
X    idx[ix++] = get_extra_ovr (sav[i++]);
X    for (; sav[i]; ++i) {
X	if (strcmp (sav[i], ",") == 0  &&  sav[i + 1])
X	    idx[ix++] = get_extra_ovr (sav[++i]);
X    }
X    idx[ix] = -1;
X    nohold_load();
X    j = 1;
X    push_break();
X    for (i = 0; i < Entries; ++i) {
X	if (mode == M_CONT  &&  Entry[i].no == 0)
X	    continue;
X	ix = ok = 0;
X	avi = 1;
X	while ((ptr = sav[avi]) != NULL) {
X	    if (ptr[0] == ','  &&  ptr[1] == '\0' && sav[avi+1]) {
X		++ix;
X		avi += 2;
X		continue;
X	    }
X	    if (not = (*ptr == '!'))
X		++ptr;
X	    len = strlen (ptr);
X	    dest = Entry[i].fields[idx[ix]];
X	    if (*ptr == '\0') {
X		ok = 1;
X		goto gotit;
X	    }
X	    while (*dest) {
X		scr = 0;
X		while (l_map[dest[scr]] == l_map[ptr[scr]] && ptr[scr])
X		    ++scr;
X		if (ptr[scr] == '\0') {
X		    ok = 1;
X		    goto gotit;
X		}
X		++dest;
X	    }
X	    ++avi;
X	}
Xgotit:
X	Entry[i].no = (ok ^ not) ? j++ : 0;
X    }
X    pop_break();
X    if (Current < 0)
X	Current = 0;
X    if (Entries) {
X	if (Entry[Current].no == 0) {
X	    Current = indexof (1);
X	    if (Current < 0) {
X		 Current = 0;
X		 return (-1);
X	    }
X	}
X    } else {
X	Current = -1;
X    }
X    return (1);
X}
X
X
END_OF_FILE
if test 13593 -ne `wc -c <'src/dmail/load_mail.c'`; then
    echo shar: \"'src/dmail/load_mail.c'\" unpacked with wrong size!
fi
# end of 'src/dmail/load_mail.c'
fi
if test -f 'src/uucico/gio.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/uucico/gio.c'\"
else
echo shar: Extracting \"'src/uucico/gio.c'\" \(16481 characters\)
sed "s/^X//" >'src/uucico/gio.c' <<'END_OF_FILE'
X
X/*
X *  GIO.C	WINDOWED G PROTOCOL
X *
X *  Rewritten from scratch, except the checksum routine which was
X *  rewritten but based on the old one.
X *
X *  WINDOW SIZE:    When changing the window size be sure there
X *		    are enough buffers available for pending txs.
X *
X *  GIO.C (c)Copyright 1989, Matthew Dillon, All Rights Reserved
X */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <exec/types.h>
X#include <proto/all.h>
X
Xvoid	FrameToPacket();
X
Xextern int debug;
Xextern int WindowOne;
X
X#define SUCCESS 0
X#define FAIL	1
X
X#define MAGIC	    0125252
X#define DLE	    0x10
X#define WINDOWSIZE  2		/*  WindowSize = 1 or 2  */
X#define SEGSIZEK    2		/*  64 bytes ??     */
X
X#define SUB1(var)   (((var)-1)&7)
X
Xtypedef unsigned char	ubyte;
Xtypedef unsigned short	uword;
X
Xtypedef struct {
X    ubyte   Dle;	/*  Literal ASCII DLE				*/
X    ubyte   K;		/*  data size 2^(K+4) except K=0 means no data  */
X    ubyte   CL,CH;	/*  MAGIC - chksum(data) ^ C        */
X    ubyte   C;
X    ubyte   X;		/*  K ^ C0 ^ C1 ^ C		    */
X} Frame;
X
Xtypedef struct {
X    ubyte   CType;	/*  bits 7-6 of C	*/
X    ubyte   CCmd;	/*  bits 5-3 of C	*/
X    ubyte   CSeq;	/*  bits 2-0 of C	*/
X    ubyte   PLen;	/*  pre-data (2 bytes) for SHORTDATA type */
X    ubyte   *Data;	/*  implies CType=LONGDATA or SHORTDATA */
X    uword   DLen;	/*  length of data	*/
X} Packet;
X
X#define CT_CONTROL	(0 << 6)
X#define CT_ALTCHN	(1 << 6)
X#define CT_LONGDATA	(2 << 6)
X#define CT_SHORTDATA	(3 << 6)
X#define CT_MASK 	(3 << 6)
X
X#define CC_CLOSE	(1 << 3)
X#define CC_RJ		(2 << 3)
X#define CC_SRJ		(3 << 3)
X#define CC_RR		(4 << 3)
X#define CC_INITC	(5 << 3)
X#define CC_INITB	(6 << 3)
X#define CC_INITA	(7 << 3)
X#define CC_MASK 	(7 << 3)
X
X#define SEQ_MASK	7
X
X#define WAIT_ACK	1
X#define WAIT_DATA	2
X#define WAIT_CONTROL	3
X
X#define MaxPktSize	4096
X
Xchar	RxBuf[MaxPktSize+4];
Xchar	TxBuf[4][MaxPktSize+4];
X
X				/*  TRANSMIT STAGE	    */
Xchar	TxSeq = 0;		/*  Last send packet	    */
Xchar	TxPend= 0;		/*  hasn't been acked yet   */
Xuword	TxWinSize;		/*  1 or 2		    */
Xuword	TxSegSize;		/*  maximum segment size    */
Xchar	TxSegK; 		/*  K for TxSegSize	    */
XPacket	TxPacket[8];		/*  contents of last packet */
X
X				/*  RECEIVE STAGE	    */
Xchar	RxSeq = 1;		/*  Next expected recv pkt  */
Xchar	RxRdy = 0;		/*  Has come in..	    */
Xchar	RxRetry = 4;
Xchar	RxNotAcked = 0; 	/*  We have yet to ack it   */
XPacket	RxPacket;		/*  The packet that has come in */
X
X/*
X *  Get Transmit Buffer.  Note that some space to the left is available
X */
X
Xchar *
XGetTxBuf()
X{
X    static int index = 0;
X
X    index = (index + 1) & 3;
X    return(TxBuf[index] + 2);
X}
X
Xint
Xgwrdata(fi)
XFILE *fi;
X{
X    int bytes;
X    char *buf = GetTxBuf();
X
X    if (debug > 7)
X	printf("GWRDATA: ");
X
X    while ((bytes = fread(buf, 1, TxSegSize, fi)) >= 0) {
X	if (SendDataPacket(buf, bytes) != SUCCESS) {
X	    if (debug > 7)
X		printf("GWR Failed\n");
X	    return(FAIL);
X	}
X	if (debug > 7)
X	    printf("\nGWROK ");
X	if (bytes == 0)
X	    break;
X	buf = GetTxBuf();
X    }
X    if (debug > 7)
X	printf("\nGWFile Last Ack\n");
X    while (TxPend) {
X	if (GetData(WAIT_ACK, NULL) == FAIL)
X	    return(FAIL);
X    }
X    return (SUCCESS);
X}
X
X/*
X *  Write message to the other guy.
X *
X *  NOTE: LONGDATA packets used exclusively and \0 fill to end.
X */
X
Xint
Xgwrmsg(str)
Xchar *str;
X{
X    int len = strlen(str) + 1;      /*  type + str + \0  */
X
X    if (debug > 8)
X	printf("GWRMSG: %s\n", str);
X
X    while (len > TxSegSize) {
X	char *buf = GetTxBuf();
X	movmem(str, buf, TxSegSize);
X	if (debug > 8)
X	    printf("GWR-SEND %d\n", TxSegSize);
X	if (SendDataPacket(buf, TxSegSize) != SUCCESS)
X	    return(FAIL);
X	len -= TxSegSize;
X	str += TxSegSize;
X    }
X
X    /*
X     *	Find optimal packet size (remember, we must force LONGDATA
X     *
X     *	Apparently packet sizes less than the agreed upon size are
X     *	not allowed ???
X     */
X
X    {
X	short siz = TxSegSize;
X	char *buf = GetTxBuf();
X#ifdef NOTDEF
X	short k = TxSegK;
X
X	while (k > 1 && (siz >> 1) >= len) {
X	    --k;
X	    siz >>= 1;
X	}
X#endif
X	if (debug > 8)
X	    printf("GWR-FNL %d %d\n", len, siz);
X
X	movmem(str, buf, len);
X	setmem(buf + len, siz - len, 0);
X	if (SendDataPacket(buf, siz) != SUCCESS) {
X	    if (debug > 8)
X		printf("GWR-FAIL\n");
X	    return(FAIL);
X	}
X    }
X    if (debug > 8)
X	printf("GWR Last Ack\n");
X    while (TxPend) {
X	if (GetData(WAIT_ACK, NULL) == FAIL)
X	    return(FAIL);
X    }
X    return (SUCCESS);
X}
X
Xint
Xgrddata(fi)
XFILE *fi;
X{
X    int bytes;
X    char *buf;
X
X    if (debug > 7)
X	printf("GRDDATA\n");
X    while ((bytes = RecvDataPacket(&buf)) > 0) {
X	if (debug > 7)
X	    printf("GRDDATA blk %d\n", bytes);
X	fwrite(buf, 1, bytes, fi);
X    }
X    if (debug > 7)
X	printf("GRDDATA end %d\n", bytes);
X    if (bytes < 0)
X	return(FAIL);
X    else
X	return(SUCCESS);
X}
X
Xgrdmsg(buf, maxlen)
Xchar *buf;
X{
X    short i;
X    short n;
X    short slen;
X    char *ptr;
X
X    i = 0;
X    if (debug > 8)
X	printf("GRDMSG\n");
X    while ((n = RecvDataPacket(&ptr)) > 0) {
X	ptr[n] = 0;
X	slen = strlen(ptr);
X	if (slen > maxlen - 1) {
X	    printf("GRDMSG: Buffer overflow!\n");
X	    return (FAIL);
X	}
X	movmem(ptr, buf + i, slen);
X	buf[i + slen] = 0;
X	if (slen != n)
X	    break;
X	i += slen;
X	maxlen -= slen;
X    }
X    if (debug > 8)
X	printf("GRDMSGEND %d (%d) %s\n", n, i, buf);
X    if (n < 0) {
X	buf[0] = 0;
X	return(FAIL);
X    }
X    return(SUCCESS);
X}
X
XSendDataPacket(buf, bytes)
Xubyte *buf;
Xint bytes;
X{
X    Packet  P;
X
X    /*
X     *	If window exhausted we must wait for at least one ack.
X     */
X
X    if (TxPend == TxWinSize) {
X	if (GetData(WAIT_ACK, NULL) == FAIL)
X	    return(FAIL);
X    }
X
X    TxSeq = (TxSeq + 1) & 7;        /*  next Tx packet  */
X
X    /*
X     *	Figure out best fit packet size.  Apparently packets smaller
X     *	then the agreed upon size are not allowed ???
X     */
X
X#ifdef NOTDEF
X    {
X	short k = TxSegK;
X	P.DLen = TxSegSize;
X	while (k > 1 && P.DLen && (P.DLen >> 1) >= bytes) {
X	    --k;
X	    P.DLen >>= 1;
X	}
X    }
X#else
X    P.DLen = TxSegSize;
X#endif
X
X    if (bytes < P.DLen) {
X	uword extra = P.DLen - bytes;
X	setmem(buf + bytes, extra, 0);
X	if (extra <= 127) {
X	    P.PLen = 1;
X	    buf[-1] = extra;
X	} else {
X	    P.PLen = 2;
X	    buf[-2] = 0x80 | extra;
X	    buf[-1] = (extra >> 7);
X	}
X	P.CType = CT_SHORTDATA;
X    } else {
X	P.PLen = 0;
X	P.CType = CT_LONGDATA;
X    }
X    P.CCmd = TxSeq << 3;	/*  transmit sequence number */
X    P.CSeq = (RxSeq - 1) & 7;   /*  last valid received pkt  */
X    P.Data = buf;
X
X    if (debug > 8)
X	printf("WRITE PACKET %d %d\n", TxSeq, P.CSeq);
X
X    if (RxNotAcked)             /*  We've acked the rx packet */
X	RxNotAcked = 0;
X
X    TxPacket[TxSeq & 7] = P;
X    ++TxPend;
X
X    WritePacket(&TxPacket[TxSeq & 7], 1);
X
X    return(SUCCESS);
X}
X
XRecvDataPacket(pbuf)
Xchar **pbuf;
X{
X    if (RxRdy == 0) {
X	if (GetData(WAIT_DATA, NULL) != SUCCESS)
X	    return(-1);
X    }
X    *pbuf = RxPacket.Data;
X    RxRdy = 0;
X    return((int)RxPacket.DLen);
X}
X
Xgturnon(master)
X{
X    Packet P;
X    short retry = 5;
X    short windowsize = WINDOWSIZE;	/*  our prefered window size */
X    short segsize = SEGSIZEK;		/*  our prefered segment size */
X
X    if (WindowOne)
X	windowsize = 1;
X
X    if (master) {
X	while (retry > 0) {
X	    WriteCtlPacket(CC_INITA | windowsize);
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITA) {
X		if (P.CSeq && P.CSeq < windowsize)
X		    windowsize = P.CSeq;
X		break;
X	    }
X	    --retry;
X	}
X	while (retry > 0) {
X	    WriteCtlPacket(CC_INITB | (segsize - 1));
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITB) {
X		if (P.CSeq < segsize - 1)
X		    segsize = P.CSeq + 1;
X		break;
X	    }
X	    --retry;
X	}
X	while (retry > 0) {
X	    WriteCtlPacket(CC_INITC | windowsize);
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITC) {
X		if (P.CSeq && P.CSeq < windowsize)
X		    windowsize = P.CSeq;
X		break;
X	    }
X	    --retry;
X	}
X    } else {
X	while (retry > 0) {
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITA) {
X		WriteCtlPacket(CC_INITA | windowsize);
X		if (P.CSeq && windowsize > P.CSeq)
X		    windowsize = P.CSeq;
X		break;
X	    }
X	    --retry;
X	}
X	while (retry > 0) {
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITB) {
X		WriteCtlPacket(CC_INITB | (segsize - 1));
X		if (P.CSeq < segsize - 1)
X		    segsize = P.CSeq + 1;
X		break;
X	    }
X	    --retry;
X	}
X	while (retry > 0) {
X	    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_INITC) {
X		WriteCtlPacket(CC_INITC | windowsize);
X		if (P.CSeq && windowsize > P.CSeq)
X		    windowsize = P.CSeq;
X		break;
X	    }
X	    --retry;
X	}
X    }
X    TxSegK = segsize;
X    TxSegSize = 1 << (TxSegK + 4);
X    TxWinSize = windowsize;
X    if (debug > 0)
X	printf("Window Size is %d\n", TxWinSize);
X    if (retry == 0)
X	return(FAIL);
X    return(SUCCESS);
X}
X
Xgturnoff()
X{
X    Packet P;
X
X    WriteCtlPacket(CC_CLOSE);
X    if (GetData(WAIT_CONTROL, &P) == SUCCESS && P.CCmd == CC_CLOSE) {
X	WriteCtlPacket(CC_RR | ((RxSeq - 1) & 7));
X	return (SUCCESS);
X    }
X    return (FAIL);
X}
X
XGetData(waitfor, p)
XPacket *p;
X{
X    Packet P;
X    short timeout;
X
X    /*
X     *	If we haven't acked the last packet we received we must do
X     *	so now before we can expect to receive another one!
X     */
X
X    if (waitfor == WAIT_ACK)
X	timeout = 20;
X    else if (waitfor == WAIT_DATA)
X	timeout = 40;
X    else
X	timeout = 40;
X
X    for (;;) {
X	if (RxNotAcked) {
X	    WriteCtlPacket(CC_RR | SUB1(RxSeq));
X	    RxNotAcked = 0;
X	}
X	if (ReadPacket(&P, timeout) == FAIL) {
X	    if (waitfor == WAIT_DATA) {
X		if (RxRetry) {
X		    --RxRetry;
X		    if (debug > 8)
X			printf("\nWAIT-DATA, TIMEOUT, SEND RJ\n");
X		    WriteCtlPacket(CC_RJ | SUB1(RxSeq));
X		    continue;
X		}
X	    }
X	    if (waitfor == WAIT_ACK) {
X		if (RxRetry) {
X		    --RxRetry;
X		    if (debug > 8)
X			printf("\nWAIT-ACK, TIMEOUT, RETRY\n");
X		    WritePacket(&TxPacket[(TxSeq - TxPend + 1) & 7], 1);
X		    continue;
X		}
X	    }
X	    if (debug > 8)
X		printf("COMPLETE FAILURE RxRetry = %d\n", RxRetry);
X	    return(FAIL);
X	}
X	RxRetry = 4;
X	switch(P.CType) {
X	case CT_CONTROL:
X	    switch(P.CCmd) {
X	    case CC_CLOSE:  /*	End of communication ... not an ACK!	   */
X		if (waitfor == WAIT_CONTROL) {
X		    *p = P;
X		    return(SUCCESS);
X		}
X		return(FAIL);
X	    case CC_RJ:     /*	Reject packet (P.CSeq == last good packet) */
X			    /*	resend last packet  */
X
X		WritePacket(&TxPacket[(P.CSeq + 1) & 7], 1);
X		{
X		    short i;
X		    for (i = 0; i < TxPend; ++i) {
X			if (P.CSeq == ((TxSeq - i) & 7))
X			    break;
X		    }
X		    if (i == TxPend)
X			printf("RJ, bad seq no: %d expected %d-%d\n", P.CSeq, (TxSeq - TxPend + 1) & 7, TxSeq);
X		}
X		break;
X	    case CC_SRJ:    /*	Selective Reject (P.CSeq == bad packet # ) */
X		return(FAIL);
X	    case CC_RR:     /*	Ack to packet  (P.CSeq == packet # acked)   */
X		if (RecvdAck(P.CSeq) == SUCCESS && waitfor == WAIT_ACK)
X		    return(SUCCESS);
X		break;
X	    case CC_INITC:
X	    case CC_INITB:
X	    case CC_INITA:
X		if (waitfor == WAIT_CONTROL) {
X		    *p = P;
X		    return(SUCCESS);
X		}
X		return(FAIL);
X	    }
X	    break;
X	case CT_ALTCHN:
X	    printf("ALTCHN packet ??\n");
X	    break;
X	case CT_LONGDATA:
X	case CT_SHORTDATA:
X	    {
X		char rxseq = P.CCmd >> 3;
X		char txack = P.CSeq;
X
X		if (RxRdy == 1) {
X		    printf("Got two receive packets without me acking!\n");
X		}
X		if (rxseq == SUB1(RxSeq)) {
X		    RxNotAcked = 1;
X		    continue;	    /*	ignore resent pkts we already have */
X		} else if (rxseq != RxSeq) {
X		    if (rxseq == ((RxSeq + 1) & 7))     /*  missed one (windowed)   */
X			WriteCtlPacket(CC_RJ | SUB1(RxSeq));
X		    printf("Received sequence %d, expected %d\n", rxseq, RxSeq);
X		    break;
X		} else {
X		    if (debug > 6)
X			printf("RECV SEQUENCE %d\n", rxseq);
X		}
X
X		RecvdAck(txack);
X
X		/*
X		 *  Delay sending the ACK back in case we can combine
X		 *  it with the next transmitted packet.
X		 */
X
X		RxNotAcked = 1; 	/*  we haven't ack'd the rx packet */
X
X		RxSeq = (RxSeq + 1) & 7;
X		RxRdy = 1;
X		RxPacket = P;
X		if (waitfor == WAIT_DATA)
X		    return(SUCCESS);
X		if (TxPend == 0 && waitfor == WAIT_ACK)
X		    return(SUCCESS);
X	    }
X	    break;
X	}
X    }
X}
X
XRecvdAck(seq)
Xchar seq;
X{
X    short i;
X    short seqbase = TxSeq - TxPend + 1;
X
X	/*
X	 *  which packet was acked?
X	 */
X
X    for (i = 0; i < TxPend; ++i) {
X	if (seq == ((seqbase + i) & 7))
X	    break;
X    }
X    if (i == TxPend) {
X	if (TxPend)
X	    printf("He acked the wrong packet! %d expected %d\n", seq, TxSeq);
X	return(FAIL);
X    }
X    if (debug > 8)
X	printf("TxPend %d ->", TxPend);
X    TxPend = TxPend - i - 1;
X    if (debug > 8)
X	printf(" %d\n", TxPend);
X    return(SUCCESS);
X}
X
XWriteCtlPacket(cc)
X{
X    Packet pk;
X
X    pk.CType = CT_CONTROL;
X    pk.CCmd  = cc & CC_MASK;
X    pk.CSeq  = cc & SEQ_MASK;
X    pk.PLen  = 0;
X    pk.DLen  = 0;
X    WritePacket(&pk, 0);
X    return(SUCCESS);
X}
X
XWritePacket(pk, async)
XPacket *pk;
X{
X    Frame   F;
X    uword   sum;
X
X    F.Dle = DLE;
X    F.C   = pk->CType | pk->CCmd | pk->CSeq;
X    F.K   = 9;
X
X    if (pk->CType == CT_SHORTDATA || pk->CType == CT_LONGDATA)
X	F.K = LenToK(pk->DLen);
X    else
X	pk->DLen = 0;
X
X    sum = MAGIC - (CheckSum(pk->Data - pk->PLen, pk->DLen) ^ F.C);
X
X    F.CH  = sum >> 8;
X    F.CL  = sum;
X    F.X   = F.K ^ F.CH ^ F.CL ^ F.C;
X
X    if (debug > 8)
X	printf("WritePacket: F.K = %d F.C = %02x\n", F.K, F.C);
X
X    if (async)
X	xwritea(&F, sizeof(F));
X    else
X	xwrite(&F, sizeof(F));      /*  write header    */
X    if (pk->DLen) {             /*  write data      */
X	if (async)
X	    xwritea(pk->Data - pk->PLen, pk->DLen);
X	else
X	    xwrite(pk->Data - pk->PLen, pk->DLen);
X    }
X    return(SUCCESS);
X}
X
XReadPacket(pk, timeout)
XPacket *pk;
X{
X    Frame   F;
X    short   c;
X    short   i = 0;
X
X    pk->Data = RxBuf;
X    pk->CType = 0xFF;
X    pk->CCmd  = 0;
X    pk->CSeq  = 0;
X
X    if (debug > 8)
X	printf("ReadPacket\n");
X    while ((c = xgetc(timeout)) != EOF) {
X	if (debug > 8)
X	    printf("RP %d %02x\n", i, c);
X
X	switch(i) {
X	case 0:
X	    if (c == DLE) {
X		F.Dle = c;
X		++i;
X	    }
X	    break;
X	case 1:
X	    F.K = c;
X	    ++i;
X	    if (c == DLE) { /*  K only valid 0-9    */
X		F.Dle = c;
X		i = 1;
X	    }
X	    break;
X	case 2:
X	    F.CL = c;
X	    ++i;
X	    break;
X	case 3:
X	    F.CH = c;
X	    ++i;
X	    break;
X	case 4:
X	    F.C = c;
X	    ++i;
X	    break;
X	case 5:
X	    F.X = c;
X	    if (F.X != (F.K ^ F.CH ^ F.CL ^ F.C)) {
X		printf("F.X failed: %02x %02x\n", F.X, (F.K ^ F.CH ^ F.CL ^ F.C));
X		i = 0;
X	    } else {	    /*	get data segment if any */
X		++i;
X	    }
X	    break;
X	}
X	if (i == 6)
X	    break;
X    }
X    if (debug > 8)
X	printf("RP Hdr i = %d, F.K = %d F.C = %02x\n", i, F.K, F.C);
X
X    if (i == 6) {       /*  Receive Data Portion    */
X	uword pktsize = 1 << (F.K + 4);
X	uword n;
X
X	if (F.K == 0 || F.K == 9)
X	    pktsize = 0;	    /*	FIXME is K=0 an illegal case? */
X
X	if (pktsize > MaxPktSize) {
X	    printf("Protocol failure pktsize %d/%d/%d\n", pktsize, TxSegSize, MaxPktSize);
X	    return (FAIL);
X	}
X	for (n = 0; n < pktsize; ++n) {
X	    if ((c = xgetc(4)) == EOF)
X		break;
X	    pk->Data[n] = c;
X	}
X	if (c != EOF) {
X	    uword hissum;
X	    uword oursum;
X	    hissum = (F.CH << 8) | F.CL;
X	    oursum = MAGIC - (CheckSum(pk->Data, pktsize) ^ F.C);
X	    if (debug > 8)
X		printf("Got Data, checking: %04x %04x\n", hissum, oursum);
X	    if (hissum == oursum) {
X		FrameToPacket(&F, pk, pk->Data);
X		return (SUCCESS);
X	    }
X	} else {
X	    FrameToPacket(&F, pk, pk->Data);    /* mainly for pk->CType */
X	    return (FAIL);
X	}
X    }
X    /*
X     *	Timeout, retry?
X     */
X    return (FAIL);
X}
X
XCheckSum(s, n)
Xubyte *s;
Xint n;
X{
X    uword sum;
X    uword x;
X    uword t;
X
X    if (n == 0)
X	return(0);
X    sum = -1;
X    x = 0;
X
X    while (n) {
X	if (sum & 0x8000)
X	    sum = (sum << 1) | 1;
X	else
X	    sum = (sum << 1);
X
X	t = sum;
X	sum += *s++;
X	x += sum ^ n;
X	if (sum <= t)
X	    sum ^= x;
X	--n;
X    }
X    return((int)sum);
X}
X
Xvoid
XFrameToPacket(fr, pk, data)
XFrame *fr;
XPacket *pk;
Xubyte *data;
X{
X    pk->CType = fr->C & CT_MASK;
X    pk->CCmd  = fr->C & CC_MASK;
X    pk->CSeq  = fr->C & SEQ_MASK;
X    switch(pk->CType) {
X    case CT_LONGDATA:
X	pk->DLen = 1 << (fr->K + 4);
X	break;
X    case CT_SHORTDATA:
X	pk->DLen = 1 << (fr->K + 4);
X	if (pk->Data[0] & 0x80) {
X	    pk->DLen -= (pk->Data[0] & 0x7F) | (pk->Data[1] << 7);
X	    if (pk->DLen < 0) {
X		printf("DLEN ERROR %d\n", pk->DLen);
X		pk->DLen = 0;
X	    }
X	    pk->Data += 2;
X	} else {
X	    pk->DLen -= *pk->Data;
X	    ++pk->Data;
X	}
X	break;
X    default:
X	pk->DLen = 0;
X	break;
X    }
X}
X
XLenToK(bytes)
Xuword bytes;
X{
X    uword n = 32;
X    uword k = 1;
X
X    while (n < bytes) {
X	n <<= 1;
X	++k;
X    }
X    if (k > 8) {
X	printf("Soft error, LenToK: %d %d %d\n", bytes, n, k);
X	k = 8;
X    }
X    return((int)k);
X}
X
END_OF_FILE
if test 16481 -ne `wc -c <'src/uucico/gio.c'`; then
    echo shar: \"'src/uucico/gio.c'\" unpacked with wrong size!
fi
# end of 'src/uucico/gio.c'
fi
echo shar: End of archive 8 \(of 16\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 16 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
	amiga@cs.odu.edu	
or	amiga@xanth.cs.odu.edu	( obsolescent mailers may need this address )
or	...!uunet!xanth!amiga	( very obsolescent mailers need this address )

Comments, questions, and suggestions should be addressed to ``amiga-request''
(please only use ``amiga'' for actual submissions) at the above addresses.