/* Copyright (C) 2004 Stefan Bellon <sbellon@sbellon.de>
 *
 * This file is part of RemotePrinterFS.
 *
 * RemotePrinterFS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * RemotePrinterFS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <string.h>

/* Kludge in order to pull in headers before including config.h/rpfs.h */
#include <oslib/os.h>
#include <kernel.h>
#define _kernel_oserror os_error const

#include "config.h"
#include "connection.h"
#include "errors.h"
#include "syslogf.h"
#include "utils.h"
#include "veneers.h"

static int filetype = 0;

os_error const *
fsentry_args_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_Args_Parameter *parm = (FSEntry_Args_Parameter*)r;
    UNUSED(pw);

    error = ERR(err_Unsupported);

    syslogf(LOG_DEBUG|LOG_INFO|LOG_NOTICE, "FSEntry_Args(%i)", parm->reason);

    switch (parm->reason)
    {
    case FSEntry_Args_Reason_ReadSequentialFilePointer:
        /* PRM 2-538. */
        /* If your filing system does not support a pointer as the
           concept is meaningless then it must return a pointer of 0, and not
           return an error */
        parm->arg.sequential_pointer = 0;
        error = NULL;
        break;

    case FSEntry_Args_Reason_FlushFileBuffer:
        /* PRM 2-542. */
        /* I don't understand why this ever gets called. */
        parm->arg.sequential_pointer = parm->arg.extent = 0;
        error = NULL;
        break;

    case FSEntry_Args_Reason_ReadFileDateStamp:
        /* PRM 2-544. */
        parm->arg.sequential_pointer = parm->arg.extent = 0;
        error = NULL;
        break;

    case FSEntry_Args_Reason_WriteSequentialFilePointer:
        /* PRM 2-538. */
        /* If your filing system does not support a pointer as the
           concept is meaningless then it must ignore the call, and not
           return an error. */
    case FSEntry_Args_Reason_WriteFileExtent:
        /* PRM 2-540. */
        /* If your filing system does not support file extents as the
           concept is meaningless then it must ignore the call, and not
           return an error. */
        error = NULL;
        break;
    }

    if (error)
        syslogf(LOG_ERR, "%s", error->errmess);

    return error;
}

os_error const *
fsentry_file_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_File_Parameter *parm = (FSEntry_File_Parameter*)r;
    UNUSED(pw);

    error = ERR(err_Unsupported);

    syslogf(LOG_DEBUG|LOG_INFO,
            "FSEntry_File(%i), filename='%s'", parm->reason, parm->name);

    switch (parm->reason)
    {
    case FSEntry_File_Reason_CreateFile:
        filetype = (parm->info.date_type.part_1 & 0xFFF00) >> 8;
        error = NULL;
        break;

    case FSEntry_File_Reason_SaveFile:
        filetype = (parm->info.date_type.part_1 & 0xFFF00) >> 8;
        {
            int handle;
            int size = parm->extras.location.end - parm->extras.location.start;
            if (size < 0) {
                syslogf(LOG_ERR, "File size in FSEntry_File_Reason_SaveFile "
                                 "does not fit into 'long long'");
                error = ERR(err_InternalError);
                return error;
            }
            error = detect_protocol(parm->special_field, size, true);
            if (error)
                return error;
            handle = connection_open(parm->special_field, size, filetype);
            if (handle == -1)
                return error;
            if (connection_write(handle,
                                 parm->extras.location.start,
                                 size) == -1)
                return error;
            if (connection_close(handle) == -1)
                return error;
        }
        filetype = 0;
        error = NULL;
        break;

    case FSEntry_File_Reason_WriteCatalogueInformation:
        /* PRM 2-547. */
        error = NULL;
        break;

    case FSEntry_File_Reason_ReadCatalogueInformation:
        /* PRM 2-549. */
        parm->reason = (FSEntry_File_Reason) 0;
        error = NULL;
        break;
    }

    if (error)
        syslogf(LOG_ERR, "%s", error->errmess);

    return error;
}

os_error const *
fsentry_func_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_Func_Parameter *parm = (FSEntry_Func_Parameter*)r;
    UNUSED(pw);

    error = ERR(err_Unsupported);

    syslogf(LOG_DEBUG|LOG_INFO,
            "FSEntry_Func(%i), filename='%s'",
            parm->reason, parm->first_parameter.name_1);

    switch (parm->reason)
    {
    case FSEntry_Func_Reason_ReadNameAndBootOptionOfDisc:
        {
            char *p = parm->second_parameter.destination_address;
            *p = strlen(CSD_Unset);
            strcpy(p+1, CSD_Unset);
        }
        error = NULL;
        break;

    case FSEntry_Func_Reason_ReadDirectoryEntriesAndInformation:
    case FSEntry_Func_Reason_ReadDirectoriesAndInformation:
    case FSEntry_Func_Reason_ReadDirectoryEntries:
        parm->third_parameter.read_number = 0;
        parm->read_offset = -1;
        error = NULL;
        break;

    case FSEntry_Func_Reason_SetCurrentDirectory:
    case FSEntry_Func_Reason_ShutDown:
        error = NULL;
        break;
    }

    if (error)
        syslogf(LOG_ERR, "%s", error->errmess);

    return error;
}

os_error const *
fsentry_gbpb_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_GBPB_Parameter *parm = (FSEntry_GBPB_Parameter*)r;
    UNUSED(parm);
    UNUSED(pw);

    syslogf(LOG_ERR, "%s", ERR(err_Unsupported)->errmess);

    return ERR(err_Unsupported);
}

os_error const *
fsentry_getbytes_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_GetBytes_Parameter *parm = (FSEntry_GetBytes_Parameter*)r;
    UNUSED(parm);
    UNUSED(pw);

    syslogf(LOG_ERR, "%s", ERR(err_Unsupported)->errmess);

    return ERR(err_Unsupported);
}

os_error const *
fsentry_open_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_Open_Parameter *parm = (FSEntry_Open_Parameter*)r;
    UNUSED(pw);

    error = ERR(err_Unsupported);

    syslogf(LOG_DEBUG|LOG_INFO,
            "FSEntry_Open(%i), filename=\"%s\", special_field=\"%s\"",
            parm->open_definition.reason,
            parm->open_definition.filename,
            parm->open_definition.special_field);

    switch (parm->open_definition.reason)
    {
    case FSEntry_Open_Reason_Update:
        error = detect_protocol(parm->open_definition.special_field, -1, true);
        if (error != NULL)
            return error;
        parm->open_result.handle =
          connection_open(parm->open_definition.special_field, -1, filetype);
        if (parm->open_result.handle != -1) {
            error = NULL;
            parm->open_result.information_word = InformationWord_WritePermitted;
            parm->open_result.buffer_size = 0;
        }
    }

    if (error)
        syslogf(LOG_ERR, "%s", error->errmess);

    return error;
}

os_error const *
fsentry_putbytes_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_PutBytes_Parameter *parm = (FSEntry_PutBytes_Parameter*)r;
    UNUSED(pw);

    syslogf(LOG_DEBUG|LOG_INFO|LOG_NOTICE,
            "FSEntry_PutBytes #%i", parm->handle);

    connection_write(parm->handle, &parm->byte_to_put, 1);

    return NULL;
}

os_error const *
fsentry_close_handler(_kernel_swi_regs *r, void *pw)
{
    FSEntry_Close_Parameter *parm = (FSEntry_Close_Parameter*)r;
    UNUSED(pw);

    syslogf(LOG_DEBUG|LOG_INFO, "FSEntry_Close #%i\n", parm->handle);

    error = (connection_close(parm->handle) == -1) ? error : 0;

    if (error)
        syslogf(LOG_ERR, "%s", error->errmess);

    filetype = 0;

    return error;
}
