# 
# $Header: rfeOpenFile.pl 24-jun-2007.22:17:18 rtakeish Exp $
#
# rfeOpenFile.pl
# 
# Copyright (c) 2005, 2007, Oracle. All rights reserved.  
#
#    NAME
#      rfeOpenFile.pl - Perl script to get file contents for Remote File Editor Page 
#                       in Edit and View Modes
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    rtakeish    06/12/07 - bug5041899, multibyte file contents not supported
#    sreddy      01/24/06 - a
#    sreddy      01/23/06 - fix bug#4968435 
#    sreddy      01/18/06 - fix bug#4955527 
#    sreddy      01/18/06 - XbranchMerge sreddy_bug-4955527 from 
#                           st_emagent_10.2.0.1.1 
#    ajere       12/07/05 - For Windows OS, call this script with commonenv.bat context
#    ajere       07/28/05 - Fix bug# 4503778 
#    ajere       06/27/05 - ajere_bug-4386234_1
#    ajere       06/27/05 - Creation

require "emd_common.pl";
use strict;
use hostGenFunctions;

#Subroutine declarations
sub openFile($);
sub performPreFileOpenChk($$$$);
sub checkWritePermission($$);

#Global variables
my $windowsOsCmd      = "cmd";
my $unixOsCmd         = "/bin/sh";

#############################################
# openFile()
# Subroutine to get file contents
#############################################
sub openFile($)
{
  #Input params
  my $osCmd           = $ARGV[0];
  my $fileName        = $ARGV[1];
  my $fileSizeLimitKB = $ARGV[2];
  my $rfeViewMode     = $ARGV[3];
  
  my $preOpenChkMsg     = "NULL";
  my $preOpenChkError   = "FALSE";
  my $fileContents      = "";
  
  #If the file name is null, return
  if (!$fileName) 
  {
    EMD_PERL_ERROR("[rfeFilerViewer.pl] Input file name is empty!\n");
    exit 1;
  }
  
  #For Windows OS, execute exec_commonenv.bat if mount_shares.bat
  #and unmount_shares.bat files exist

  if (($osCmd eq $windowsOsCmd) && 
       !defined($ENV{EM_AGENT_COMMONENV_BAT_EXEC}) &&
       (-e "$ENV{EMDROOT}/bin/mount_shares.bat") &&
       (-e "$ENV{EMDROOT}/bin/unmount_shares.bat"))
  {
    #save STDERR into STDERZR_ORIG. Upon failure, skip exec_commonenv.bat step
    if (open (STDERR_ORIG, ">&STDERR"))
    {
      #send STDERR to null device. Upon failure, skip exec_commonenv.bat step
      if (open (STDERR, ">/dev/null"))
      {
        my $beginToken="BEGIN_REMOTE_OP_RESULT_SET_AFTER_COMMONENV_BAT";
        my $endToken="END_REMOTE_OP_RESULT_SET_AFTER_COMMONENV_BAT";
        my $beginTokenFound=0;
        my $line;

        #Batch file exec_commonenv.bat sets EM_AGENT_COMMONENV_BAT_EXEC and
        #call this script again after network shares from mount_shares.bat
        #are mounted. This block won't get executed then and the array 
        #scriptResult will contain actual output within start and end tokens.

        my @scriptResult=`$ENV{EMDROOT}\\bin\\exec_commonenv.bat rfeOpenFile.pl @ARGV`;

        #restore STDERR to STDERR_ORIG
        close(STDERR);
        open (STDERR, ">&STDERR_ORIG")
          or EMD_PERL_ERROR("rfeOpenFile.pl: Failed to restore STDERR"); 

        #Note: There is no good reason why the above open will fail. Upon
        #failure, there is no need to exit since result will be sent 
        #on STDOUT back to OMS
 
        #Extract actual output of this script
        chomp @scriptResult;
        foreach $line (@scriptResult)
        {
          if ($line =~ $endToken)
          {
            print "$`"; #prints the content on last line 
                        #if it does not end with <LF>
            exit 0;
          }
          print "$line\n" if ($beginTokenFound eq 1);
          $beginTokenFound=1 if ($line =~ $beginToken);
        }
        exit 0;
      }
      else
      {
        EMD_PERL_ERROR("rfeOpenFile.pl: Failed to redirect STDERR to null device");
      }
    }
    else
    {
      EMD_PERL_ERROR("rfeOpenFile.pl: Failed to save STDERR into STDERR_ORIG");
    }
  }
  
  #Default fileSizeLimitKB is 100 KB
  if(!$fileSizeLimitKB || !($fileSizeLimitKB =~ /\d/)) 
  {
    $fileSizeLimitKB = 100;
  }
  #print "fileSizeLimitKB = $fileSizeLimitKB\n";
    
  #Perform pre-open file checks
  ($preOpenChkMsg, $preOpenChkError) = performPreFileOpenChk($osCmd, $fileName, $fileSizeLimitKB, $rfeViewMode);
  
  #Get the file contents, iff pre-open checks indicate file can be opened
  if(($preOpenChkMsg ne "FILE_DOESNT_EXIST")&&($preOpenChkError eq "FALSE"))
  {
    #Open the file
    if (!open(FH, "$fileName")) 
    { 
      EMD_PERL_ERROR("[rfeFilerViewer.pl] Unable to open the file $fileName for reading!\n");
      exit 1;
    } 
    
    #Go to EOF
    seek(FH,0,2);
  
    #Get the file size and start point
    my $fileSize = (-s $fileName);
    my $startPoint = $fileSize - $fileSizeLimitKB*1000;
    if($startPoint < 0) 
    {
      $startPoint = 0;
    }
    #print "startPoint = $startPoint\n";
  
    #Seek to the start point
    if(!seek(FH, $startPoint, 0)) 
    {
      EMD_PERL_ERROR("[rfeFilerViewer.pl] Unable to seek to the start point of the file $fileName!\n");
      exit 1;
    }
  
    #Get file contents in chunks
    my $bufferSizeBytes = 1000;
    my $line;
    while(read(FH, $line, $bufferSizeBytes))
    {
      $fileContents.= $line;
    }
  
    #Full contents not read!
    if($startPoint ne 0)
    {
      $preOpenChkMsg = "RFE_SHOWING_PARTIAL_CONTENTS_VIEW_MODE";
    }
   
    #Close the file
    close FH;
  }
  
  return $preOpenChkMsg."|".$preOpenChkError."\n"."$fileContents";
}

#############################################
# performPreFileOpenChk()
# Subroutine to Perform pre-open file checks
#############################################
sub performPreFileOpenChk($$$$) 
{
  my $osCmd           = $_[0];
  my $fileName        = $_[1];
  my $fileSizeLimitKB = $_[2];
  my $rfeViewMode     = $_[3];
  my $directory       = $fileName;
  
  #Pre-open check logic
  #File is a directory file!
  return ("FILE_IS_DIRECTORY", "TRUE")
    if(-d $fileName);

  #Get the parent directory
  if ($osCmd eq $windowsOsCmd) 
  {
    #Windows
    if($fileName =~ /(.*\\)/) 
    {
      $directory = $1;
    }
  } 
  elsif ($osCmd eq $unixOsCmd) 
  {
    #UNIX
    if ($fileName =~ m!(.*\/)!) 
    {
      $directory = $1;
    }
  }
  #print ("directory = $directory\n");	
  
  #File doesn't exist
  if (!-e $fileName) 
  {
    #Edit Mode
    if($rfeViewMode eq "FALSE")
    {
      #Parent directory has write permissions
      if (-d $directory && -w $directory)
      {
        my $writePermission=1;

        $writePermission = checkWritePermission($fileName, $osCmd);

        return ("FILE_DOESNT_EXIST", "FALSE")
          if ($writePermission);
      }

      #Parent directory doesn't have write permissions!
      return ("NO_CREATE_PERMISSIONS", "TRUE");
    }
    else
    {
      return ("FILE_DOESNT_EXIST_VIEW_MODE", "TRUE");
    }
  }
  else
  {
    #No read permissions!
    if (!-r $fileName) 
    {
      return ("CANT_ACCESS_FILE", "TRUE");
    }
    
    #Not a text file!
    if (!-T $fileName) 
    {
      #Perl limitation workaround - bug# 4503778, bug# 5041899
      #For UNIX OS and Windows OS, re-check whether it's really a non-text file
      if(!hostGenFunctions::isTextFile($fileName, $osCmd))
      {
        return ("NON_EDITABLE_FILE_CONTENTS", "TRUE");
      }
    }
    
    #Edit Mode
    if($rfeViewMode eq "FALSE")
    {
      #File is greater than maximum limit!
      if (($fileSizeLimitKB =~ /\d/) && ((-s $fileName) > $fileSizeLimitKB*1000)) 
      {
        return ("FILE_TOO_BIG", "TRUE");
      }

      my $writePermission = checkWritePermission($fileName, $osCmd);

      return ("NO_WRITE_PERMISSIONS", "FALSE")
        if (!$writePermission);
    }
  }

  #No message & no errors
  return ("NULL", "FALSE");
}

###########################################################
# checkWritePerssion()
# Subroutine to test if it is possible to write to the file
###########################################################

sub checkWritePermission($$)
{
  my $fname = shift @_;
  my $osCmd = shift @_;
  my $writePermission = 0;

  if ($osCmd eq $unixOsCmd)
  {
    $writePermission = 1 if ((! -e $fname) || (-w $fname));
  }
  elsif ($osCmd eq $windowsOsCmd)
  {

#
# On Windows, if (-w $fname) test sometimes returns true
# value even if the file is not writeable. This can happen
# on a directory where the user is not granted FULL 
# privileges. This subroutine verifies the write permission
# by opening the file in append mode. It cleans up the
# file if it did not exist before the file was opened
# in append mode.
#
# This is one of the issues fixed as part of  bug#4968435
#
    my $removeFile = 0;
    $removeFile = 1 if ( ! -e $fname );

    if (open(TEST_FH,">>$fname"))
    {
      $writePermission=1;
      close(TEST_FH);
      unlink($fname) if ($removeFile);
    }
  }
  
  return $writePermission;
}

#For Windows OS only
if ($ARGV[0] eq $windowsOsCmd && defined($ENV{EM_AGENT_COMMONENV_BAT_EXEC}))
{
  my $openFileRes = openFile(@ARGV);
  print "$openFileRes";
  exit 0;
}

return 1;
