
/* Handler fuer UMS */

//+ includes, defines, structs
#include    <exec/types.h>
#include    <exec/nodes.h>
#include    <exec/ports.h>
#include    <exec/memory.h>
#include    <dos/dos.h>
#include    <dos/dosextens.h>
#include    <dos/filehandler.h>

#include    <clib/dos_protos.h>
#include    <clib/exec_protos.h>
#include    <clib/alib_protos.h>
#include    <clib/ums_protos.h>

#include    <stdio.h>
#include    <stdarg.h>
#include    <stdlib.h>
#include    <string.h>

#include    "libraries/UMS.h"
#include    "DLIB:UMSMatchConfigTags.c"
#include    "DLIB:UMSReadMsgTags.c"
#include    "DLIB:UMSWriteMsgTags.c"
#include    "DLIB:UMSReadConfigTags.c"
#include    "DLIB:UMSWriteConfigTags.c"
#include    "DLIB:UMSSearchTags.c"
#include    "DLIB:UMSSelectTags.c"

#define     DOS_TRUE    -1
#define     DOS_FALSE   0

#define     CTOB( x)    ( BPTR)(( ULONG)( x) >> 2)
#define     BTOC( x)    ( APTR)(( ULONG)( x) << 2)

struct  UMSFileHandle
{
    struct StoredMSGHeader  *ufh_Data;

    long    ufh_DataSeek;
    long    ufh_DataSize;
    long    ufh_MsgNumber;

    UMSUserAccount  ufh_Account;
};

struct  UMSLock
{
    struct FileLock     ul_Lock;

    long    ul_MsgNumber;
    long    ul_LockType;

    BSTR    ul_FileName[ 108 ];

    UMSUserAccount  ul_Account;
};

struct  StoredMSGHeader
{
    char    smh_FromUserName[ 36 ];
    char    smh_ToUserName[ 36 ];
    char    smh_Subject[ 72 ];
    char    smh_DateTime[ 20 ];

    long    smh_TimesRead;
    long    smh_DestNode;
    long    smh_OrigNode;
    long    smh_Cost;
    long    smh_OrigNet;
    long    smh_DestNet;
    long    smh_DestZone;
    long    smh_OrigZone;
    long    smh_DestPoint;
    long    smh_OrigPoint;
    long    smh_ReplyTo;
    long    smh_Attribute;
    long    smh_NextReply;

    char    smh_Text[ 0 ];
};

#define     STRING_LENGTH       60
//-

void ReturnPacket( struct DosPacket *);
void Initialize( void);
void UnInitialize( void);

struct DeviceNode   *DeviceNode;
struct MsgPort      *PacketPort;
struct Library      *UMSBase    = NULL;

const char  *Version    = "$VER: UMS-handler 1.0 (22.07.95)";

char    UserName[ STRING_LENGTH ];

/*
 *  Note that we use the _main entry point.  Also notice that we do not
 *  need to open any libraries.. they are openned for us via DICE's
 *  unique auto-library-open ability.
 */

void _main()
{
    struct DosPacket  *Packet;

    {
        struct Process *ThisProcess = FindTask( NULL);
        PacketPort = &ThisProcess->pr_MsgPort;
    }

    Initialize();

    /*
     *  Main Loop
     */

    while( TRUE)
    {
        {
            struct Message *PaketMsg;

            while(( PaketMsg = GetMsg( PacketPort)) == NULL)            /* auf Msg warten */
                Wait( 1 << PacketPort->mp_SigBit);

            Packet = ( struct DosPacket *) PaketMsg->mn_Node.ln_Name;       /* ln_Name = Zeiger auf Paket! */
        }

        /*
         *  default return value = alles o.k.!
         */

        if( Packet)
        {
            Packet->dp_Res1 = DOS_TRUE;
            Packet->dp_Res2 = 0;

            switch( Packet->dp_Type)
            {
//+               ACTION_DIE
                case ACTION_DIE :
                {
                    ReturnPacket( Packet);

                    UnInitialize();
                    _exit( 0);
                }
                break;

//-
/*                case ACTION_FINDOUTPUT:
                case ACTION_FINDUPDATE: */
//+               ACTION_FINDINPUT
                case ACTION_FINDINPUT :
                {
                    struct FileHandle       *fh     = BTOC( Packet->dp_Arg1);
                    struct UMSFileHandle    *ufh    = NULL;

                    char    *MsgText;
                    char    *MsgSubject;
                    char    *MsgFromName;
                    char    *MsgToName;

                    char    *StartPointer;
                    char    *EndPointer;

                    fh->fh_Port = ( struct MsgPort *) DOS_FALSE;

                    if( StartPointer = ( char *) BTOC( Packet->dp_Arg3) + 1)
                    {
                        StartPointer[ ( int) *StartPointer - 1 ] = 0x00;

                        while( *StartPointer && *StartPointer++ != ':');

                        EndPointer = StartPointer;

                        while( *EndPointer && *EndPointer++ != '/');

                        if( *EndPointer)
                        {
                            if( fh->fh_Arg1 = ufh = AllocVec( sizeof( struct UMSFileHandle), MEMF_ANY|MEMF_CLEAR))
                            {
                                if(( ufh->ufh_Account = UMSRLogin( "", UserName, "")) > NULL)
                                {
                                    *( EndPointer - 1) = 0x00;

                                    UMSSelectTags( ufh->ufh_Account,
                                                   UMSTAG_SelWriteLocal,    TRUE,
                                                   UMSTAG_SelSet,           0,
                                                   UMSTAG_SelUnset,         ( 1L<<0) | ( 1L<<1),
                                                   TAG_DONE);

                                    if( UMSSelectTags( ufh->ufh_Account,
                                                       UMSTAG_SelWriteLocal,    TRUE,
                                                       UMSTAG_SelSet,           ( 1L<<0),
                                                       UMSTAG_SelUnset,         0,
                                                       UMSTAG_SelMask,          UMSUSTATF_ReadAccess |
                                                                                UMSUSTATF_ViewAccess,
                                                       UMSTAG_SelMatch,         UMSUSTATF_ReadAccess |
                                                                                UMSUSTATF_ViewAccess,
                                                       UMSTAG_WGroup,           StartPointer,
                                                       TAG_DONE))
                                    {
                                        ufh->ufh_MsgNumber = atol( EndPointer);

                                        if( UMSSelectTags( ufh->ufh_Account,
                                                           UMSTAG_SelWriteLocal,    TRUE,
                                                           UMSTAG_SelSet,           ( 1L<<1),
                                                           UMSTAG_SelUnset,         0,
                                                           UMSTAG_SelMask,          UMSUSTATF_ReadAccess |
                                                                                    UMSUSTATF_ViewAccess,
                                                           UMSTAG_SelMatch,         UMSUSTATF_ReadAccess |
                                                                                    UMSUSTATF_ViewAccess,
                                                           UMSTAG_SelMsg,           ufh->ufh_MsgNumber,
                                                           TAG_DONE))
                                        {
                                            if( UMSSelectTags( ufh->ufh_Account,
                                                               UMSTAG_SelReadLocal,    TRUE,
                                                               UMSTAG_SelSet,           0,
                                                               UMSTAG_SelUnset,         0,
                                                               UMSTAG_SelMask,          ( 1L<<0) | ( 1L<<1),
                                                               UMSTAG_SelMatch,         ( 1L<<0) | ( 1L<<1),
                                                               TAG_DONE))
                                            {
                                                if( ReadUMSMsgTags( ufh->ufh_Account,
                                                                    UMSTAG_RMsgNum,     ufh->ufh_MsgNumber,
                                                                    UMSTAG_RMsgText,    &MsgText,
                                                                    UMSTAG_RSubject,    &MsgSubject,
                                                                    UMSTAG_RFromName,   &MsgFromName,
                                                                    UMSTAG_RToName,     &MsgToName,
                                                                    TAG_DONE))
                                                {
                                                    ufh->ufh_DataSize = sizeof( struct StoredMSGHeader) + strlen( MsgText) + 1;

                                                    if( ufh->ufh_Data = AllocVec( ufh->ufh_DataSize, MEMF_ANY|MEMF_CLEAR))
                                                    {
                                                        strncpy( ufh->ufh_Data->smh_Subject,        MsgSubject,     71);
                                                        strncpy( ufh->ufh_Data->smh_FromUserName,   MsgFromName,    35);
                                                        strncpy( ufh->ufh_Data->smh_ToUserName,     MsgToName,      35);

                                                        strcpy( ufh->ufh_Data->smh_Text, MsgText);
                                                    }
                                                    else Packet->dp_Res2 = ERROR_NO_FREE_STORE;
                                                }
                                                else Packet->dp_Res2 = ERROR_READ_PROTECTED;
                                            }
                                            else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                        }
                                        else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                    }
                                    else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                }
                                else Packet->dp_Res2 = ERROR_NO_DISK;

                                if( Packet->dp_Res2)
                                {
                                    if( ufh)
                                    {
                                        if( ufh->ufh_Account > NULL)
                                        {
                                            if( ufh->ufh_Data) FreeVec( ufh->ufh_Data);

                                            FreeUMSMsg( ufh->ufh_Account, ufh->ufh_MsgNumber);
                                            UMSLogout( ufh->ufh_Account);
                                        }

                                        FreeVec( ufh);
                                        fh->fh_Arg1 = NULL;
                                    }
                                }
                            }
                            else Packet->dp_Res2 = ERROR_NO_FREE_STORE;
                        }
                        else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                    }
                }
                break;
//-
//+               ACTION_READ
                case ACTION_READ :
                {
                    struct UMSFileHandle    *ufh = ( struct UMSFileHandle *) Packet->dp_Arg1;

                    if( Packet->dp_Arg3 > ufh->ufh_DataSize - ufh->ufh_DataSeek)
                        Packet->dp_Res1 = ufh->ufh_DataSize - ufh->ufh_DataSeek;
                    else
                        Packet->dp_Res1 = Packet->dp_Arg3;

                    memcpy(( void *) Packet->dp_Arg2, ufh->ufh_Data + ufh->ufh_DataSeek, Packet->dp_Res1);

                    ufh->ufh_DataSeek += Packet->dp_Res1;
                }
                break;
//-
/*                case ACTION_WRITE :
                {
                    struct FileHandle   *fh = BTOC( Packet->dp_Arg1);
                }
                break; */

//+               ACTION_SEEK
                case ACTION_SEEK :
                {
                    struct UMSFileHandle    *ufh = ( struct UMSFileHandle *) Packet->dp_Arg1;

                    Packet->dp_Res1 = ufh->ufh_DataSeek;

                    switch( Packet->dp_Arg3)
                    {
                        case OFFSET_BEGINNING :
                        {
                            if( ufh->ufh_DataSize >= Packet->dp_Arg2 >= 0) ufh->ufh_DataSeek = Packet->dp_Arg2;
                            else Packet->dp_Res1 = -1;
                        }
                        break;

                        case OFFSET_CURRENT :
                        {
                            if( ufh->ufh_DataSize >= ufh->ufh_DataSeek + Packet->dp_Arg2 >= 0) ufh->ufh_DataSeek += Packet->dp_Arg2;
                            else Packet->dp_Res1 = -1;
                        }
                        break;

                        case OFFSET_END :
                        {
                            if( ufh->ufh_DataSize >= -( Packet->dp_Arg2) >= 0) ufh->ufh_DataSeek = ufh->ufh_DataSize - Packet->dp_Arg2;
                            else Packet->dp_Res1 = -1;
                        }
                        break;
                    }

                    if( Packet->dp_Res1 == -1) Packet->dp_Res2 = ERROR_SEEK_ERROR;
                }
                break;

//-
//+               ACTION_END
                case ACTION_END :
                {
                    struct UMSFileHandle    *ufh = ( struct UMSFileHandle *) Packet->dp_Arg1;

                    FreeUMSMsg( ufh->ufh_Account, ufh->ufh_MsgNumber);
                    UMSLogout( ufh->ufh_Account);

                    FreeVec( ufh->ufh_Data);
                    FreeVec( ufh);
                }
                break;
//-

//+               ACTION_LOCATE_OBJECT
                case ACTION_LOCATE_OBJECT :
                {
                    struct UMSLock  *ResultLock;

                    char    FullName[ 180 ];

                    char    *StartPointer;
                    char    *EndPointer;

                    if( ResultLock = AllocVec( sizeof( struct UMSLock), MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR))
                    {
                        ResultLock->ul_Lock.fl_Access   = Packet->dp_Arg3;
                        ResultLock->ul_Lock.fl_Task     = DeviceNode->dn_Task;
                        ResultLock->ul_Lock.fl_Volume   = CTOB( DeviceNode);

                        if( StartPointer = BTOC( Packet->dp_Arg2))
                        {
                            StartPointer[ ( int) *StartPointer + 1 ] = 0x00;

                            while( *StartPointer && *StartPointer++ != ':');

                            if( *StartPointer)                      /* Mehr als nur Volume? */
                            {
                                memcpy( ResultLock->ul_FileName, BTOC( Packet->dp_Arg2), 108 /*( int) *( char *)BTOC( Packet->dp_Arg2)*/);

                                EndPointer = StartPointer;

                                while( *EndPointer && *EndPointer != '/')
                                    EndPointer++;

                                if( *EndPointer) *EndPointer++ = 0x00;

                                if(( ResultLock->ul_Account = UMSRLogin( "", UserName, "")) > NULL)
                                {
                                    UMSSelectTags( ResultLock->ul_Account,
                                                   UMSTAG_SelWriteLocal,    TRUE,
                                                   UMSTAG_SelSet,           0,
                                                   UMSTAG_SelUnset,         ( 1L<<0) | ( 1L<<1),
                                                   TAG_DONE);

                                    if( UMSSelectTags( ResultLock->ul_Account,
                                                       UMSTAG_SelWriteLocal,    TRUE,
                                                       UMSTAG_SelSet,           ( 1L<<0),
                                                       UMSTAG_SelUnset,         0,
                                                       UMSTAG_SelMask,          UMSUSTATF_ReadAccess |
                                                                                UMSUSTATF_ViewAccess,
                                                       UMSTAG_SelMatch,         UMSUSTATF_ReadAccess |
                                                                                UMSUSTATF_ViewAccess,
                                                       UMSTAG_WGroup,           StartPointer,
                                                       TAG_DONE))
                                    {
                                        if( *EndPointer)        /* noch mehr als nur Dir? */
                                        {
                                            ResultLock->ul_MsgNumber = atol( EndPointer);

                                            if( UMSSelectTags( ResultLock->ul_Account,
                                                               UMSTAG_SelWriteLocal,    TRUE,
                                                               UMSTAG_SelSet,           ( 1L<<1),
                                                               UMSTAG_SelUnset,         0,
                                                               UMSTAG_SelMask,          UMSUSTATF_ReadAccess |
                                                                                        UMSUSTATF_ViewAccess,
                                                               UMSTAG_SelMatch,         UMSUSTATF_ReadAccess |
                                                                                        UMSUSTATF_ViewAccess,
                                                               UMSTAG_SelMsg,           ResultLock->ul_MsgNumber,
                                                               TAG_DONE))
                                            {
                                                if( UMSSelectTags( ResultLock->ul_Account,
                                                                   UMSTAG_SelReadLocal,    TRUE,
                                                                   UMSTAG_SelSet,           0,
                                                                   UMSTAG_SelUnset,         0,
                                                                   UMSTAG_SelMask,          ( 1L<<0) | ( 1L<<1),
                                                                   UMSTAG_SelMatch,         ( 1L<<0) | ( 1L<<1),
                                                                   TAG_DONE))
                                                {
                                                    ResultLock->ul_LockType = ST_FILE;
                                                }
                                                else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                            }
                                            else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                        }
                                        else
                                        {
                                            ResultLock->ul_LockType = ST_USERDIR;
                                        }
                                    }
                                    else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
                                }
                                else Packet->dp_Res2 = ERROR_NO_DISK;
                            }
                            else
                            {
                                memcpy( ResultLock->ul_FileName, &DeviceNode->dn_Name, 108 /*( int) DeviceNode->dn_Name*/);
                                ResultLock->ul_LockType = ST_ROOT;
                            }
                        }
                        else Packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;

                        if( Packet->dp_Res2)
                        {
                            if( ResultLock)
                            {
                                if( ResultLock->ul_Account > NULL)
                                {
                                    UMSLogout( ResultLock->ul_Account);
                                }

                                FreeVec( ResultLock);
                                ResultLock = NULL;
                            }
                        }
                    }
                    else Packet->dp_Res2 = ERROR_NO_FREE_STORE;

                    Packet->dp_Res1 = CTOB( ResultLock);
                }
                break;
//-
//+               ACTION_FREE_LOCK
                case ACTION_FREE_LOCK :
                {
                    struct UMSLock  *ResultLock;

                    if( ResultLock = BTOC( Packet->dp_Arg1))
                    {
                        UMSLogout( ResultLock->ul_Account);
                        ResultLock->ul_Lock.fl_Task = NULL;

                        FreeVec( ResultLock);
                    }
                }
                break;
//-
//+               ACTION_EXAMINE_OBJECT
                case ACTION_EXAMINE_OBJECT :
                {
                    struct UMSLock          *FileLock;
                    struct FileInfoBlock    *ResultFIB;

                    if( ResultFIB = BTOC( Packet->dp_Arg2))
                    {
                        if( FileLock = BTOC( Packet->dp_Arg1))
                        {
                            memcpy( ResultFIB->fib_FileName, FileLock->ul_FileName, 108 /*( int) FileLock->ul_FileName*/);
                            ResultFIB->fib_DirEntryType = FileLock->ul_LockType;
                        }
                        else
                        {
                            memcpy( ResultFIB->fib_FileName, &( DeviceNode->dn_Name), 108 /*( int) DeviceNode->dn_Name*/);
                            ResultFIB->fib_DirEntryType = ST_ROOT;
                        }

                        ResultFIB->fib_DiskKey      = 0;
                        ResultFIB->fib_Protection   = 0;
                        ResultFIB->fib_EntryType    = ResultFIB->fib_DirEntryType;
                        ResultFIB->fib_Size         = 0;
                        ResultFIB->fib_NumBlocks    = 0;
                        ResultFIB->fib_Comment[ 0 ] = 0;
                    }
                    else Packet->dp_Res2 = ERROR_NO_FREE_STORE;
                }
                break;
//-
//+               ACTION_COPY_DIR
                case ACTION_COPY_DIR :
                {
                    struct UMSLock          *FileLock;
                    struct UMSLock          *ResultLock;

                    if( ResultLock = AllocVec( sizeof( struct UMSLock), MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR))
                    {
                        if( FileLock = BTOC( Packet->dp_Arg1))
                        {
                            memcpy( ResultLock, FileLock, sizeof( struct UMSLock));
                        }
                        else
                        {
                            ResultLock->ul_Lock.fl_Access   = SHARED_LOCK;
                            ResultLock->ul_Lock.fl_Task     = DeviceNode->dn_Task;
                            ResultLock->ul_Lock.fl_Volume   = CTOB( DeviceNode);
                            ResultLock->ul_LockType         = ST_ROOT;
                            memcpy( ResultLock->ul_FileName, &( DeviceNode->dn_Name), 108 /*( int) DeviceNode->dn_Name*/);
                        }
                    }
                    else Packet->dp_Res2 = ERROR_NO_FREE_STORE;

                    Packet->dp_Res1 = CTOB( ResultLock);
                }
                break;
//-
//+               ACTION_PARENT
                case ACTION_PARENT :
                {
                    struct UMSLock          *FileLock;
                    struct UMSLock          *ResultLock;

                    if( FileLock = BTOC( Packet->dp_Arg1))
                    {
                        if( memcmp( FileLock->ul_FileName, &( DeviceNode->dn_Name), ( int) FileLock->ul_FileName))
                        {
                            Packet->dp_Res1 = 0;
                        }
                        else
                        {
                            if( ResultLock = AllocVec( sizeof( struct UMSLock), MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR))
                            {
                                ResultLock->ul_Lock.fl_Access   = SHARED_LOCK;
                                ResultLock->ul_Lock.fl_Task     = DeviceNode->dn_Task;
                                ResultLock->ul_Lock.fl_Volume   = CTOB( DeviceNode);
                                memcpy( ResultLock->ul_FileName, FileLock->ul_FileName, 108 /*( int) DeviceNode->dn_Name*/);

                                Packet->dp_Res1 = CTOB( ResultLock);
                            }
                            else Packet->dp_Res2 = ERROR_NO_FREE_STORE;
                        }
                    }
                    else Packet->dp_Res1 = 0;
                }
                break;
//-

                default:
                {
                    Packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
                }
                break;
            }

            if( Packet->dp_Res2) Packet->dp_Res1 = DOS_FALSE;

            ReturnPacket( Packet);
        }
    }
}

/*
 *  Packet ROUTINES.    Dos Packets are in a rather strange format as you
 *  can see by this and how the Packet structure is extracted in the
 *  GetMsg() of the main routine.
 */

//+ void ReturnPacket( struct DosPacket *Packet)
void ReturnPacket( struct DosPacket *Packet)
{
    struct Message *Msg;
    struct MsgPort *ReplyPort;

    ReplyPort                = Packet->dp_Port;
    Msg                      = Packet->dp_Link;
    Packet->dp_Port          = PacketPort;
    Msg->mn_Node.ln_Name     = ( char *) Packet;
    PutMsg( ReplyPort, Msg);
}//-

/*
 *  During initialization DOS sends us a Packet and sets our dn_SegList
 *  pointer.  If we set our dn_Task pointer than every Open's go to the
 *  same handler (this one).  If we set dn_Task to NULL, every Open()
 *  will create a NEW instance of this process via the seglist, meaning
 *  our process must be reentrant (i.e. -r option).
 *
 *  note: dn_Task points to the MESSAGE PORT portion of the process
 *  (or your own custom message port).
 *
 *  If we clear the SegList then we also force DOS to reload our process
 *  from disk, but we also need some way of then UnLoadSeg()ing it ourselves,
 *  which we CANNOT do from this process since it rips our code out from
 *  under us.
 */

//+ void Initialize()
void Initialize()
{
    struct DosPacket   *Packet;

    char    *String;

    {
        struct Message  *InitialMsg;

        WaitPort( PacketPort);
        InitialMsg = GetMsg( PacketPort);
        Packet = ( struct DosPacket *) InitialMsg->mn_Node.ln_Name;
    }

    DeviceNode = BTOC( Packet->dp_Arg3);
    DeviceNode->dn_Task = PacketPort;
/*    DeviceNode->dn_Task = NULL;       */

    Packet->dp_Res2 = 0;

    if( UMSBase = ( struct Library *) OpenLibrary( "ums.library", 11L))
    {
        String = BTOC( Packet->dp_Arg2);

        memcpy( UserName, String + 1, ( int) *String);
        UserName[ ( int) *String ] = 0x00;
    }
    else Packet->dp_Res2 = ERROR_DEVICE_NOT_MOUNTED;

    if( Packet->dp_Res2) Packet->dp_Res1 = DOS_FALSE;
    else                 Packet->dp_Res1 = DOS_TRUE;

    ReturnPacket( Packet);
}
//-
//+ void UnInitialize( void)
void UnInitialize( void)
{
    {
        DeviceNode->dn_Task    = NULL;
        DeviceNode->dn_SegList = NULL;
    }

    if( UMSBase)    CloseLibrary( UMSBase);
}
//-
