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.