CREATE OR REPLACE PACKAGE mip_virus_check IS

  -- Author  : HARDYA
  -- Created : 23/01/2008 09:55:52
  -- Purpose : Virus checking package
  -- Updates : MULLENMD - added functionality to run the virus checker for a file
  --
  PROCEDURE write_file(p_name     IN wwv_flow_files.NAME%TYPE
                      ,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
                      ,p_fs_name  IN VARCHAR2);
                      
  /**
      check_file - allows MIP to run an anti-virus scan on a given file
      
      %param p_name - the APEX name of the file
      %param p_location - the directory on the server where the file will be tested
      %param p_fs_name - the actual filename of the file to test
    */
  PROCEDURE check_file(p_name     IN wwv_flow_files.NAME%TYPE
                      ,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
                      ,p_fs_name  IN VARCHAR2);
  --
END mip_virus_check;
/
CREATE OR REPLACE PACKAGE BODY mip_virus_check IS

  PROCEDURE write_file(p_name     IN wwv_flow_files.NAME%TYPE
                      ,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
                      ,p_fs_name  IN VARCHAR2) IS
    l_lob_loc     BLOB;
    l_buffer      RAW(32767);
    l_buffer_size BINARY_INTEGER;
    l_amount      BINARY_INTEGER;
    l_offset      NUMBER(38) := 1;
    l_chunksize   INTEGER;
    l_out_file    utl_file.file_type;
  
  BEGIN
  
    SELECT blob_content
      INTO l_lob_loc
      FROM wwv_flow_files
     WHERE NAME = p_name;
  
    l_chunksize := dbms_lob.getchunksize(l_lob_loc);
  
    IF (l_chunksize < 32767) THEN
      l_buffer_size := l_chunksize;
    ELSE
      l_buffer_size := 32767;
    END IF;
  
    l_amount := l_buffer_size;
  
    dbms_lob.OPEN(l_lob_loc
                 ,dbms_lob.lob_readonly);
  
    l_out_file := utl_file.fopen(location     => p_location
                                ,filename     => p_fs_name
                                ,open_mode    => 'wb'
                                ,max_linesize => 32767);
  
    WHILE l_amount >= l_buffer_size LOOP
    
      dbms_lob.READ(lob_loc => l_lob_loc
                   ,amount  => l_amount
                   ,offset  => l_offset
                   ,buffer  => l_buffer);
    
      l_offset := l_offset + l_amount;
    
      utl_file.put_raw(file      => l_out_file
                      ,buffer    => l_buffer
                      ,autoflush => TRUE);
    
      --utl_file.fflush(file => l_out_file);
    
    END LOOP;
  
    utl_file.fflush(file => l_out_file);
  
    utl_file.fclose(l_out_file);
  
    dbms_lob.CLOSE(l_lob_loc);
  END write_file;

  --
  FUNCTION trigger_av_scan(p_location IN VARCHAR2
                          ,p_fs_name  IN VARCHAR2) RETURN BOOLEAN IS
  BEGIN
    NULL;
  EXCEPTION
    WHEN OTHERS THEN
      RETURN NULL;
  END trigger_av_scan;
  --

  --
  FUNCTION check_file_exists(p_location IN VARCHAR2
                            ,p_fs_name  IN VARCHAR2) RETURN BOOLEAN IS
    l_file_exists BOOLEAN;
    l_file_length NUMBER;
    l_block_size  NUMBER;
  BEGIN
    utl_file.fgetattr(location => p_location
                     ,filename => p_fs_name
                     ,fexists => l_file_exists
                     ,file_length => l_file_length
                     ,block_size => l_block_size);
                               
    RETURN l_file_exists;
  EXCEPTION
    WHEN OTHERS THEN 
      RETURN FALSE;
  END check_file_exists;
  --
  
  --
  PROCEDURE delete_file_from_server(p_location IN VARCHAR2
                                   ,p_fs_name  IN VARCHAR2) IS
  BEGIN
    utl_file.fremove(location => p_location
                    ,filename => p_fs_name);
  END delete_file_from_server;
  --
  
  --
  PROCEDURE delete_file_from_MIP(p_name IN wwv_flow_files.NAME%TYPE) IS
  BEGIN
    NULL;
  END delete_file_from_MIP;
  --
  
  --
  PROCEDURE check_file(p_name     IN wwv_flow_files.NAME%TYPE,
                       p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
                       p_fs_name  IN VARCHAR2) IS
    av_scan_result BOOLEAN;
    file_result    BOOLEAN;
  BEGIN
    -- write the file to the file system, trigger a scan, check if the file is still there
    -- and then act accordingly if it isn't.
    write_file(p_name     => p_name,
               p_location => p_location,
               p_fs_name  => p_fs_name);
  
    av_scan_result := trigger_av_scan(p_location => p_location,
                                      p_fs_name  => p_fs_name);
  
    IF av_scan_result THEN
      file_result := check_file_exists(p_location => p_location,
                                       p_fs_name  => p_fs_name);
    
      IF NOT file_result THEN
        delete_file_from_mip(p_name => p_name);
      ELSE
        delete_file_from_server(p_location => p_location,
                                p_fs_name  => p_fs_name);
      END IF;
    ELSE
      raise_application_error(-20099,
                              'Error whilst running anti-virus on file ' ||
                              p_fs_name);
    END IF;
  END check_file;
  --
    
BEGIN
  -- Initialization
  NULL;
END mip_virus_check;
/
