头图

症状
a) 您需要将文件从 SAP 应用程序服务器传输到仅支持 SFTP 协议的接收方。但是,SAP 应用程序服务器只能使用 HTTPS 协议发送文件。此外,您可能希望在发送前对文件进行加密。

b) 您需要通过 HTTPS 将文件从远程服务器传输到 SAP 应用程序服务器。此外,您可能希望在保存之前解密文件。

目前没有标准的程序或工具可用于文件加密、解密和传输。因此,您需要创建一个自定义程序。本说明为您提供示例编码以支持您创建自己的程序。

请注意:PGP 加密不是SAP Employee Central Payroll 服务产品的一部分。原因如下: PGP 需要在应用服务器上安装额外的操作级软件,这在云环境中是不可能的

其他条款
SAP SuccessFactors Employee Central Payroll、SFTP 服务器、文件传输、加密、解密

原因和先决条件
在使用您的自定义程序之前,必须满足以下先决条件:

您有权创建报告程序、从应用程序服务器检索文件以及将它们上传到远程服务器。
在本地服务器上启动用于出站处理的程序的用户对本地文件具有 READ 授权:授权对象 S_DATASET、PROGRAM = SAPLSCMS_FILE、ACTVT = 33(读取)、FILENAME = <本地文件名,包括完整路径>。
请注意:这并不一定意味着该用户可以显示文件内容。例如,如果您既未在程序中使用值帮助,也未授予用户对象 S_TCODE 和 TCD = AL11 的授权,则他们将无法从 UI 访问文件内容。
在 FILE 事务中,您维护了传出和传入文件的逻辑路径和文件名。
在 SM59 事务中,您维护了一个类型为 G =“HTTP 连接到外部服务器”的 RFC 目标,并将远程服务器作为目标主机。您已在“登录和安全”选项卡上维护了远程服务器的用户名和密码。两个系统中必要的基本配置都已完成(例如,在系统中建立可信连接、授权等)。要创建到外部服务器的 HTTPS 连接,Employee Central Payroll 系统必须信任服务器的证书。
要使用 SSL 连接,您需要通过 STRUST 事务附加外部服务器的 CA 证书。示例报告使用默认客户端 PSE(SSL 客户端标准)连接到远程服务器。
您已成功执行 RFC 目标的连接测试。
仅相关,如果您想使用加密功能:
在 STRUST 事务中,您维护了一个 PSE 并导入了您要发送的文件的最终收件人的证书。有关 STRUST 的更多信息,请参阅https://help.sap.com/viewer/2...
解决方案
SAP SuccessFactors 为客户提供对 SFTP 服务器的访问。您可以先通过HTTPS从ABAP应用服务器向这个SFTP服务器发送文件,然后再通过SFTP协议从SFTP服务器传输给接收方。除了使用 SuccessFactors SFTP 服务器,您还可以将文件发送到任何其他通过 HTTPS 协议接受文件的远程服务器。

本笔记所附的示例代码显示,

a) 来自 ABAP 应用程序服务器的文件如何通过 HTTPS 检索、加密和发送到远程服务器

b) 如何通过 HTTPS 检索来自远程服务器的文件、解密并将其存储在 ABAP 应用程序服务器上。

示例程序只为 PSE 和收件人提供一对输入字段。在生产场景中,您不会使用相同的 PSE 和收件人进行加密和解密。但是在您的实施和测试阶段,您可能想要检查是否正确调用了加密功能。为此,输入 PSE 所有者作为接收者(证书主题):只有这样,您才能在同一个 PSE 中同时拥有用于加密的公钥和用于解密的私钥。

如果您对加密或解密有任何问题,请检查系统日志(SM21 事务)以获取有关问题根源的信息。

示例程序使用您在 SM59 事务中维护的 RFC 连接。如果您将目标系统的凭据存储在该 RFC 连接中,您可以安排程序并将其作为后台作业运行:凭据将从 SM59 配置中获取,并且在文件传输期间不会提示您输入它们。

注意:在创建自己的程序时,请特别注意示例代码中以“@CUSTOMER”开头的注释,因为您需要实现自己的逻辑。通过示例程序的流程逻辑,您可以看到如何调用功能(本地读/写、http 文件传输、解密/加密)。

注意:示例编码并非旨在高效使用,SAP 既不提供任何支持,也不对您基于此示例可能实施的任何内容负责。这尤其适用于安全问题:您有责任为您的编码添加安全功能,并相应地配置您的系统(例如,保护您的系统免受病毒侵害)。

注意:示例程序中使用的 SSF_KRN_ENVELOPE 和 SSF_KRN_DEVELOPE 密码功能模块仅支持公钥密码标准 PKCS#7。非对称密钥必须是 RSA 或 ECDSA。支持的对称密码算法请参考 SAP note 2004653的对应部分。如果要显示所有支持的密码标准的列表,请启动事务 SE38,输入Program Name = SSF02并执行 (F8)。在选项部分,选择SSF 格式字段的值帮助以显示该列表。如果您使用SSFW_KRN_ENVELOPE和SSFW_KRN_DEVELOPE 功能模块,您可以使用这些标准中的任何一个加密/解密文件。

要在您自己的系统中实现示例程序,请执行以下操作:

1.在SE38事务中,新建一个程序。例如,ZSAMPLE_CRYPT_TRANSFER_FILE 或选择任何其他名称。

  1. 在编辑器中,选择Utilities -> More Utilities -> Upload/Download 并将附件(ZSAMPLE_CRYPT_TRANSFER_FILE.txt)上传 到该程序中。
  2. 激活程序。
  3. 选择Goto -> Text Elements为每个选择参数和选择屏幕的每个块定义文本。
    您会在选择文本的选项卡上找到一些条目:这些条目是在程序激活期间根据选择参数自动生成的,现在您只需填写文本。通过双击程序中块标题的文本符号 text-<xyz>
    为文本符号创建条目。适当的文本包含在示例编码中,作为每个选择参数或块标题旁边的注释,您可以简单地将它们从那里复制到选择文本或文本符号中。

提示:您将在示例编码的末尾找到选择屏幕的定义。

  1. 激活文本。

sap 官方snote

*&---------------------------------------------------------------------*
REPORT zsample_crypt_transfer_file.
*&---------------------------------------------------------------------*
*&
*& Sample report for
*&  a) transferring a file from the application server
*&     to an external file server via HTTP(S) protocol
*&     Optionally, the file can be encrypted before sending
*&  b) fetching a file from an external server via HTTP(S) and
*&     saving it to the application server.
*&     Optionally, the file can be decrypted before saving
*&
*& !!! Basic example only - coding needs to be adapted by customer!!!
*&
*& For adapting to customer specific needs, pay special attention
*& to comments marked with '@CUSTOMER'
*&
*& !!! MESSAGE and WRITE statements              !!!
*& !!! to be used only for testing in dialog mode!!!
*& Define appropriate messages and write to application log
*& in order to run the program in batch mode
*&
*&---------------------------------------------------------------------*
*& M O D I F I C A T I O N   L O G                                     *
*&---------------------------------------------------------------------*
*& Date         Author        Description                              *
*&---------------------------------------------------------------------*
*& yyyy-mm-dd   XXXXXXXXXX    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*
*&
*&---------------------------------------------------------------------*


* ======================================================================
* Local classes
* ======================================================================


* ======================================================================
* lcl_file:
* Represents the file, provides basic operations like SAVE, and
* cryptographic operations
* =====================================================================
CLASS lcl_file DEFINITION FINAL.

  PUBLIC SECTION.

    TYPES:
      tty_line TYPE STANDARD TABLE OF ssfdata .

    CONSTANTS gc_mode_orig TYPE c VALUE '1' ##NO_TEXT.
    CONSTANTS gc_mode_decrypted TYPE c VALUE '2' ##NO_TEXT.
    CONSTANTS gc_mode_encrypted TYPE c VALUE '3' ##NO_TEXT.
    CONSTANTS gc_line_length TYPE i VALUE 255 ##NO_TEXT.

    METHODS save
      IMPORTING
        !iv_pathname TYPE fileintern
        !iv_mode     TYPE flag DEFAULT '2' .
    METHODS encrypt
      IMPORTING
        !iv_pse       TYPE ssfappl
        !iv_recipient TYPE certsubjct
      RAISING
        cx_crypto_error .
    METHODS decrypt
      IMPORTING
        !iv_pse       TYPE ssfappl
        !iv_recipient TYPE certsubjct
      RAISING
        cx_crypto_error .
    METHODS create_from_xstring
      IMPORTING
        !iv_xstring  TYPE xstring
        !iv_pathname TYPE string
        !iv_bytes    TYPE i OPTIONAL .
    METHODS load_from_applsrv
      IMPORTING
        !iv_pathname    TYPE fileintern
        !iv_filename    TYPE string
      RETURNING
        VALUE(rv_subrc) TYPE i .
    METHODS get_mimetype
      RETURNING
        VALUE(rv_mimetype) TYPE w3conttype .
    METHODS get_xstring
      IMPORTING
        !iv_mode    TYPE c
      EXPORTING
        !ev_xstring TYPE xstring
        !ev_length  TYPE i
        !ev_subrc   TYPE sysubrc .

  PRIVATE SECTION.

    DATA: mv_extension        TYPE string,
          mt_decrypted_line   TYPE tty_line,
          mt_encrypted_line   TYPE saml2_pse_bin_data_t,
          mt_source_line      TYPE tty_line,
          mv_decrypted_length TYPE i,
          mv_encrypted_length TYPE i,
          mv_filename         TYPE string,
          mv_source_length    TYPE i,
          mv_mimetype         TYPE w3conttype.

    METHODS set_name_and_type
      IMPORTING
        !iv_pathname TYPE string .
ENDCLASS.



CLASS lcl_file IMPLEMENTATION.

  METHOD create_from_xstring.
*      IMPORTING
*        !iv_xstring  TYPE xstring
*        !iv_pathname TYPE string
*        !iv_bytes    TYPE i OPTIONAL .

    " -------------------------------------------------------------
    " Creates file content from given xstring and sets some
    " instance attributes.
    " Method can be used e.g. after retrieving a file via HTTP GET
    " -------------------------------------------------------------

    DATA:
      lv_xstring TYPE xstring,
      lv_line    TYPE ssfdata.

    lv_xstring = iv_xstring.

    IF iv_bytes IS INITIAL.
      mv_source_length = xstrlen( lv_xstring ).
    ELSE.
      mv_source_length = iv_bytes.
    ENDIF.

    WHILE xstrlen( lv_xstring ) > 0.
      lv_line = lv_xstring.
      APPEND lv_line TO mt_source_line.
      SHIFT lv_xstring LEFT BY gc_line_length PLACES IN BYTE MODE.
    ENDWHILE.

    set_name_and_type( iv_pathname ).

  ENDMETHOD.


  METHOD decrypt.
*      IMPORTING
*        !iv_pse       TYPE ssfappl
*        !iv_recipient TYPE certsubjct
*      RAISING
*        cx_crypto_error .

    " -----------------------------------------------------------------
    " Decrypts the binary content of the original file and
    " puts the result into mt_decrypted_line
    " -----------------------------------------------------------------

    FIELD-SYMBOLS:
      <ls_source_line> TYPE ssfdata.

    DATA:
      ls_encrypted_line TYPE ssfbin,
      lt_encrypted_line TYPE saml2_pse_bin_data_t,
      lv_ssftoolkit     TYPE  ssftoolkit,
      lv_str_format     TYPE  ssfform,
      lv_str_profile    TYPE  ssfprof,
      lv_crc            TYPE  ssfreturn,
      lt_recipient      TYPE TABLE OF ssfinfo,
      ls_recipient      TYPE ssfinfo.


    " Before decrypting, we need to re-format the content:
    " Decryption works with a structured line type, but
    " the original content has a flat line type
    LOOP AT mt_source_line ASSIGNING <ls_source_line>.
      CLEAR ls_encrypted_line.
      ls_encrypted_line-bindata = <ls_source_line>.
      APPEND ls_encrypted_line TO lt_encrypted_line.
    ENDLOOP.

    CALL FUNCTION 'SSF_GET_PARAMETER'
      EXPORTING
        mandt       = sy-mandt
        application = iv_pse
      IMPORTING
        ssftoolkit  = lv_ssftoolkit
        str_format  = lv_str_format
        str_profile = lv_str_profile
      EXCEPTIONS
        OTHERS      = 1.
    IF sy-subrc <> 0.
      WRITE: / 'SSF parameter read failed - see system log (SM21)'.
      RAISE EXCEPTION TYPE cx_crypto_error.
    ENDIF.

    " function module needs a recipient list:
    ls_recipient-id = iv_recipient.
    ls_recipient-profile = lv_str_profile.
    APPEND ls_recipient TO lt_recipient.

    CALL FUNCTION 'SSF_KRN_DEVELOPE'
      EXPORTING
        ssftoolkit            = lv_ssftoolkit
        str_format            = lv_str_format
        ostr_enveloped_data_l = mv_source_length
      IMPORTING
        ostr_output_data_l    = mv_decrypted_length
        crc                   = lv_crc
      TABLES
        ostr_enveloped_data   = lt_encrypted_line
        recipient             = lt_recipient
        ostr_output_data      = mt_decrypted_line
      EXCEPTIONS
        OTHERS                = 1.
    IF sy-subrc <> 0 OR lv_crc <> 0 OR mt_decrypted_line IS INITIAL.
      WRITE: / 'Decryption for file ', mv_filename, ' failed - see system log (SM21)'.
      RAISE EXCEPTION TYPE cx_crypto_error.
    ELSE.
      WRITE: / 'File ', mv_filename, ' decrypted'.
    ENDIF.

  ENDMETHOD.


  METHOD encrypt.
*      IMPORTING
*        !iv_pse       TYPE ssfappl
*        !iv_recipient TYPE certsubjct
*      RAISING
*        cx_crypto_error .

    " ---------------------------------------------------------------------------
    " Encrypts the original binary file content using the given PSE and recipient,
    " and puts the result into mt_encrypted_line
    " ---------------------------------------------------------------------------

    DATA:
      lv_ssftoolkit       TYPE  ssftoolkit,
      lv_str_format       TYPE  ssfform,
      lv_str_pab          TYPE  ssfpab,
      lv_str_pab_password TYPE  ssfpabpw,
      lv_crc              TYPE  ssfreturn,
      lt_recipient        TYPE TABLE OF ssfinfo,
      ls_recipient        TYPE ssfinfo.

    CALL FUNCTION 'SSF_GET_PARAMETER'
      EXPORTING
        mandt            = sy-mandt
        application      = iv_pse
      IMPORTING
        ssftoolkit       = lv_ssftoolkit
        str_format       = lv_str_format
        str_pab          = lv_str_pab
        str_pab_password = lv_str_pab_password
      EXCEPTIONS
        OTHERS           = 1.
    IF sy-subrc <> 0.
      WRITE: / 'SSF parameter read failed - see system log (SM21)'.
      RAISE EXCEPTION TYPE cx_crypto_error.
    ENDIF.

    " put the specified recipient into the list:
    ls_recipient-id = iv_recipient.
    APPEND ls_recipient TO lt_recipient.

    CALL FUNCTION 'SSF_KRN_ENVELOPE'
      EXPORTING
        ssftoolkit            = lv_ssftoolkit
        str_format            = lv_str_format
        ostr_input_data_l     = mv_source_length
        str_pab               = lv_str_pab
        str_pab_password      = lv_str_pab_password
      IMPORTING
        ostr_enveloped_data_l = mv_encrypted_length
        crc                   = lv_crc
      TABLES
        ostr_input_data       = mt_source_line
        recipient_list        = lt_recipient
        ostr_enveloped_data   = mt_encrypted_line
      EXCEPTIONS
        OTHERS                = 1.
    IF sy-subrc <> 0 OR lv_crc <> 0 OR mt_encrypted_line IS INITIAL.
      WRITE: / 'File ', mv_filename, ': encryption failed - see system log (SM21)'.
      RAISE EXCEPTION TYPE cx_crypto_error.
    ELSE.
      WRITE: / 'File ', mv_filename, ' encrypted'.
    ENDIF.

  ENDMETHOD.


  METHOD get_mimetype.
*      RETURNING
*        VALUE(rv_mimetype) TYPE w3conttype .
    rv_mimetype = mv_mimetype.
  ENDMETHOD.


  METHOD get_xstring.
*      IMPORTING
*        !iv_mode    TYPE c
*      EXPORTING
*        !ev_xstring TYPE xstring
*        !ev_length  TYPE i
*        !ev_subrc   TYPE sysubrc .

    " -------------------------------------------------------------
    " Returns the file content as xstring
    " Depending on iv_mode, the original, decrypted or encrypted
    " content is returned:
    "  1 = original
    "  2 = decrypted
    "  3 = encrypted
    " -------------------------------------------------------------

    CONSTANTS lc_line_length TYPE i VALUE 255.
    FIELD-SYMBOLS <fs_line> TYPE ssfbin.

    DATA:
      lt_line             TYPE tty_line,
      lv_length           TYPE i,
      lv_cumulated_length TYPE i.


    CLEAR:
       ev_xstring,
       ev_length,
       ev_subrc.


    CASE iv_mode.
      WHEN gc_mode_encrypted.
        " Line type is structured -> requires special handling
        lv_length = mv_encrypted_length.
        LOOP AT mt_encrypted_line ASSIGNING <fs_line>.
          " append current line at the correct position
          CONCATENATE ev_xstring(lv_cumulated_length) <fs_line>-bindata INTO ev_xstring IN BYTE MODE.
          lv_cumulated_length = lv_cumulated_length + lc_line_length.
        ENDLOOP.
        " set xstring to correct length (as provided by the encryption routine)
        ev_xstring = ev_xstring(mv_encrypted_length).
        ev_length = mv_encrypted_length.
        RETURN.
      WHEN gc_mode_orig.
        lv_length = mv_source_length.
        lt_line = mt_source_line.
      WHEN gc_mode_decrypted.
        lv_length = mv_decrypted_length.
        lt_line = mt_decrypted_line.
      WHEN OTHERS.
        ev_subrc = 1.
        RETURN.
    ENDCASE.

    " Original and decrypted lines both have unstructured line type
    CONCATENATE LINES OF lt_line INTO ev_xstring IN BYTE MODE.
    " set xstring to correct length:
    " wrong length may cause errors in subsequent processing
    ev_xstring = ev_xstring(lv_length).
    ev_length = lv_length.

  ENDMETHOD.


  METHOD load_from_applsrv.
*      IMPORTING
*        !iv_pathname    TYPE fileintern
*        !iv_filename     TYPE string
*      RETURNING
*        VALUE(rv_subrc) TYPE i .

    " -------------------------------------------------------------
    " Reads the file content from the specified location on the
    " application server and sets some instance attributes
    " -------------------------------------------------------------

    DATA:
      lv_filename(400) TYPE c,
      lv_msg           TYPE string,
      lv_flag          TYPE abap_bool,
      lv_pathname      TYPE string,
      lv_message       TYPE string.

    CLEAR rv_subrc.

    " ------------------------------------------------------------------
    " !!! Programming guidelines !!!
    " Prevent unauthorized file access by using
    " logical paths and file names
    " ------------------------------------------------------------------

    CALL FUNCTION 'FILE_GET_NAME'
      EXPORTING
        logical_filename = iv_pathname
        parameter_1      = iv_filename
      IMPORTING
        emergency_flag   = lv_flag
        file_name        = lv_pathname
      EXCEPTIONS
        file_not_found   = 1
        OTHERS           = 2.

    rv_subrc = sy-subrc.
    IF rv_subrc <> 0 OR lv_flag IS NOT INITIAL.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
        INTO lv_message.
      WRITE: / lv_message.
      WRITE: / 'ERROR in FILE_GET_NAME - file will not be processed.'.
      RETURN.
    ENDIF.

    CALL FUNCTION 'FILE_VALIDATE_NAME'
      EXPORTING
        logical_filename           = iv_pathname
        parameter_1                = iv_filename
      CHANGING
        physical_filename          = lv_pathname
      EXCEPTIONS
        logical_filename_not_found = 1
        validation_failed          = 2
        OTHERS                     = 3.
    rv_subrc = sy-subrc.

    IF rv_subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
        INTO lv_message.
      WRITE: / lv_message.
      WRITE: / 'ERROR in FILE_VALIDATE_NAME - file will not be processed.'.
      RETURN.
    ENDIF.

    " Read as BINARY in order to handle all mime types correctly
    lv_filename = lv_pathname.
    CALL FUNCTION 'SCMS_UPLOAD'
      EXPORTING
        filename = lv_filename " full name including path
        binary   = 'X'
        frontend = space
      IMPORTING
        filesize = mv_source_length
      TABLES
        data     = mt_source_line
      EXCEPTIONS
        error    = 1
        OTHERS   = 2.
    rv_subrc = sy-subrc.
    IF rv_subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                 WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO lv_msg.
      WRITE: / lv_msg.
      RETURN.
    ENDIF.

    set_name_and_type( lv_pathname ).

  ENDMETHOD.


  METHOD save.
*      IMPORTING
*        !iv_pathname TYPE fileintern
*        !iv_mode     TYPE flag DEFAULT '2' .

    " ----------------------------------------------------------------------
    " Saves the file to the target folder on the application server.
    " Depending on iv_mode, the original, decrypted or encrypted file
    " shall be saved:
    "  1 = original
    "  2 = decrypted
    "  3 = encrypted
    " ----------------------------------------------------------------------

    DATA:
      lv_pathname  TYPE string,
      lv_line      TYPE ssfdata,
      lt_line      TYPE tty_line,
      lv_length    TYPE i,
      lv_cryptinfo TYPE string,
      lv_message   TYPE string,
      lv_flag      TYPE abap_bool.

    FIELD-SYMBOLS:
          <fs_line> TYPE ssfbin.


    " ----------------------------------------------------------------------------
    " !!! Programming guidelines !!!
    " Prevent unauthorized file access by using
    " logical paths and file names
    " ----------------------------------------------------------------------------

    CALL FUNCTION 'FILE_GET_NAME'
      EXPORTING
        logical_filename = iv_pathname
        parameter_1      = mv_filename
      IMPORTING
        emergency_flag   = lv_flag
        file_name        = lv_pathname
      EXCEPTIONS
        file_not_found   = 1
        OTHERS           = 2.

    IF sy-subrc <> 0 OR lv_flag IS NOT INITIAL.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
        INTO lv_message.
      WRITE: / lv_message.
      WRITE: / 'ERROR in FILE_GET_NAME - file will not be stored.'.
      RETURN.
    ENDIF.

    CALL FUNCTION 'FILE_VALIDATE_NAME'
      EXPORTING
        logical_filename           = iv_pathname
        parameter_1                = mv_filename
      CHANGING
        physical_filename          = lv_pathname
      EXCEPTIONS
        logical_filename_not_found = 1
        validation_failed          = 2
        OTHERS                     = 3.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
        INTO lv_message.
      WRITE: / lv_message.
      WRITE: / 'ERROR in FILE_VALIDATE_NAME - file will not be stored.'.
      RETURN.
    ENDIF.

    " consolidate different data tables and formats
    CASE iv_mode.
      WHEN gc_mode_encrypted.
        lv_cryptinfo = 'Encrypted file '.
        " Line type is structured -> requires special handling
        lv_length = mv_encrypted_length.
        LOOP AT mt_encrypted_line ASSIGNING <fs_line>.
          APPEND <fs_line>-bindata TO lt_line.
        ENDLOOP.
      WHEN gc_mode_orig.
        lv_cryptinfo = 'Original file '.
        lv_length = mv_source_length.
        lt_line = mt_source_line.
      WHEN gc_mode_decrypted.
        lv_cryptinfo = 'Decrypted file '.
        lv_length = mv_decrypted_length.
        lt_line = mt_decrypted_line.
      WHEN OTHERS.
        RETURN.
    ENDCASE.

    IF lv_length > 0.
      " Could be 0 e.g. if you are trying to save the decrypted version of
      " a file that has never been decrypted.

      OPEN DATASET lv_pathname FOR OUTPUT IN BINARY MODE.
      LOOP AT lt_line INTO lv_line.
        IF lv_length LT gc_line_length. "255.
          TRANSFER lv_line(lv_length) TO lv_pathname.
          EXIT. "from LOOP
        ELSE.
          TRANSFER lv_line TO lv_pathname.
          lv_length = lv_length - gc_line_length.
        ENDIF.
      ENDLOOP.
      CLOSE DATASET lv_pathname.
      WRITE: / lv_cryptinfo, ' saved: ', lv_pathname.
    ELSE.
      WRITE: / lv_cryptinfo,  mv_filename, ' is empty - not saved'.
    ENDIF.

  ENDMETHOD.


  METHOD set_name_and_type.
*      IMPORTING
*        !iv_pathname TYPE string .

    " ----------------------------------------------
    " Determines file name and mime type
    " and stores them in instance attributes
    " ----------------------------------------------

    DATA:
      lt_string    TYPE string_table,
      lv_count     TYPE i,
      lv_extension TYPE w3fileext.


    CALL FUNCTION 'TRINT_SPLIT_FILE_AND_PATH'
      EXPORTING
        full_name     = iv_pathname
      IMPORTING
        stripped_name = mv_filename
      EXCEPTIONS
        x_error       = 1
        OTHERS        = 2.
    IF sy-subrc <> 0.
      WRITE: /'ERROR when splitting path.'.
      RETURN.
    ENDIF.

    CLEAR lt_string.
    SPLIT mv_filename AT '.' INTO TABLE lt_string.
    DESCRIBE TABLE lt_string LINES lv_count.
    IF lv_count GT 1.
      READ TABLE lt_string INTO mv_extension INDEX lv_count.
    ENDIF.

    " string variable mv_extension cannot be passed into the function module
    " SDOK_MIMETYPE_GET will set a default if there is no extension
    lv_extension = mv_extension.
    CALL FUNCTION 'SDOK_MIMETYPE_GET'
      EXPORTING
        extension = lv_extension
      IMPORTING
        mimetype  = mv_mimetype.

  ENDMETHOD.
ENDCLASS.

* ======================================================================
* lcl_file_http:
* Utility class for http file transfer in both directions
* ======================================================================
CLASS lcl_file_http DEFINITION FINAL.

  PUBLIC SECTION.

    METHODS constructor
      IMPORTING
        !iv_rfc_dest TYPE rfcdest
      RAISING
        !cx_dest_http_abap_special
      .

    METHODS send
      IMPORTING
        !iv_target_folder TYPE string
        !iv_file_name     TYPE string
        !iv_content_type  TYPE string
        !iv_content       TYPE xstring
        !iv_bytes         TYPE i.

    METHODS get
      IMPORTING
        !iv_source_path TYPE string
      EXPORTING
        !ev_content     TYPE xstring
        !ev_bytes       TYPE i
        !ev_subrc       TYPE sysubrc .

  PRIVATE SECTION.

    DATA mr_client TYPE REF TO if_http_client .
    CONSTANTS mc_protocol TYPE string VALUE 'HTTP/1.1' ##NO_TEXT.

    METHODS set_uri
      IMPORTING
        !iv_file_name     TYPE string
        !iv_target_folder TYPE string
      RETURNING
        VALUE(rv_uri)     TYPE string .
ENDCLASS.



CLASS lcl_file_http IMPLEMENTATION.

  METHOD constructor.
*      IMPORTING
*        !iv_rfc_dest TYPE rfcdest
*      RAISING
*        !cx_dest_http_abap_special


    DATA: lv_rfc_dest  TYPE char32.

    lv_rfc_dest = iv_rfc_dest.

    " create http client for file transfer
    CALL METHOD cl_http_client=>create_by_destination
      EXPORTING
        destination              = lv_rfc_dest
      IMPORTING
        client                   = mr_client
      EXCEPTIONS
        argument_not_found       = 1
        destination_not_found    = 2
        destination_no_authority = 3
        plugin_not_active        = 4
        internal_error           = 5
        OTHERS                   = 6.

    IF sy-subrc IS NOT INITIAL.
      " not semantically fitting, but nothing better available in package SHTTP
      RAISE EXCEPTION TYPE cx_dest_http_abap_special.
    ENDIF.

  ENDMETHOD.


  METHOD get.
*      IMPORTING
*        !iv_source_path TYPE string
*      EXPORTING
*        !ev_content     TYPE xstring
*        !ev_bytes       TYPE i
*        !ev_subrc       TYPE sysubrc .

    " ----------------------------------------------------------------
    " Sets request attributes,
    " gets file from the remote server,
    " and handles errors
    " ----------------------------------------------------------------

    DATA: lv_xstring     TYPE xstring,
          lv_path        TYPE string,
          lr_http_entity TYPE REF TO if_http_entity,
          lv_code        TYPE i,
          lv_reason      TYPE string.

    CLEAR ev_subrc.
    CLEAR ev_bytes.
    CLEAR ev_content.

    CALL METHOD mr_client->refresh_request
      EXCEPTIONS
        http_action_failed = 1
        OTHERS             = 2.
    IF sy-subrc <> 0.
      WRITE: / 'Could not refresh HTTP client - processing terminated.'.
      RETURN.
    ENDIF.

    CONCATENATE '/' iv_source_path INTO lv_path.
    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>request_uri
        value = mr_client->create_abs_url( path = lv_path ).

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>request_method
        value = 'GET'.

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>server_protocol
        value = mc_protocol.

    CALL METHOD mr_client->send
      EXPORTING
        timeout = 0
      EXCEPTIONS
        OTHERS  = 0.

    CALL METHOD mr_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3
        OTHERS                     = 4.

    IF sy-subrc NE 0.
      ev_subrc = sy-subrc.
      WRITE:/ 'ERROR for file ',  iv_source_path, ': GET failed'.
      WRITE:/ '    Reason: '.
      CASE ev_subrc.
        WHEN 1.
          WRITE 'http communication failure'.
        WHEN 2.
          WRITE 'http invalid state'.
        WHEN 3.
          WRITE 'http processing failed'.
        WHEN OTHERS.
          WRITE 'not specified'.
      ENDCASE.
      RETURN.
    ENDIF.

    " Check the status of the response:
    " Previous method calls may not have raised an exception
    " even though the GET was not successful (e.g. if the file was not found)
    CALL METHOD mr_client->response->get_status
      IMPORTING
        code   = lv_code
        reason = lv_reason.

    IF lv_code = '200'. " 200 = everything OK
      lr_http_entity ?= mr_client->response.
      " -----------------------------------------------------------------------
      " @CUSTOMER:
      " !!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      " !!! Activate the virus scan when retrieving data from the remote server
      " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      " -----------------------------------------------------------------------
      CALL METHOD lr_http_entity->get_data
        EXPORTING
          vscan_scan_always = if_http_entity=>co_content_check_always " !!! switch on virus scan !!!
        RECEIVING
          data              = lv_xstring.

      IF lv_xstring IS INITIAL.
        ev_subrc = 1.
        WRITE: / 'ERROR: method GET_DATA returned an empty xstring for file ', iv_source_path.
        RETURN.
      ENDIF.

      ev_content = lv_xstring.
      ev_bytes = xstrlen( lv_xstring ).

    ELSE.
      WRITE:/ 'HTTP ERROR for file: ', iv_source_path, ',   Code: ',  lv_code, ',  Reason: ', lv_reason.
      ev_subrc = 1.
    ENDIF.

  ENDMETHOD. "get


  METHOD send.
*      IMPORTING
*        !iv_target_folder TYPE string
*        !iv_file_name     TYPE string
*        !iv_content_type  TYPE string
*        !iv_content       TYPE xstring
*        !iv_bytes         TYPE i.

    " ----------------------------------------------------------------
    " Sets request attributes,
    " sends file to the remote server,
    " and handles errors
    " ----------------------------------------------------------------

    DATA:
      lv_code   TYPE i,
      lv_reason TYPE string.


    CALL METHOD mr_client->refresh_request
      EXCEPTIONS
        http_action_failed = 1
        OTHERS             = 2.
    IF sy-subrc <> 0.
      WRITE: / 'Could not refresh HTTP client - processing terminated.'.
      RETURN.
    ENDIF.

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>request_uri
        value = set_uri( iv_target_folder = iv_target_folder
                         iv_file_name     = iv_file_name ).

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>request_method
        value = 'PUT'.

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = if_http_header_fields_sap=>server_protocol
        value = mc_protocol.

    CALL METHOD mr_client->request->set_header_field
      EXPORTING
        name  = 'content-type'
        value = iv_content_type.

    CALL METHOD mr_client->request->set_data
      EXPORTING
        data   = iv_content
        length = iv_bytes.

    CALL METHOD mr_client->send
      EXPORTING
        timeout = 0.

    CALL METHOD mr_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3
        OTHERS                     = 4.

    IF sy-subrc NE 0.
      WRITE:/ 'ERROR for file ',  iv_file_name, ': creation of remote file failed'.
      WRITE:/ '    Reason: '.
      CASE sy-subrc.
        WHEN 1.
          WRITE 'http communication failure'.
        WHEN 2.
          WRITE 'http invalid state'.
        WHEN 3.
          WRITE 'http processing failed'.
        WHEN OTHERS.
          WRITE 'not specified'.
      ENDCASE.
    ELSE.
      CALL METHOD mr_client->response->get_status
        IMPORTING
          code   = lv_code
          reason = lv_reason.

      IF lv_code = '201'. " 201 = Created
        WRITE: / 'File ', iv_file_name, ' sent.'.
      ELSE.
        WRITE:/ 'HTTP ERROR when sending file: ', iv_file_name, ',   Code: ',  lv_code, ',  Reason: ', lv_reason.
      ENDIF.
    ENDIF.

  ENDMETHOD.



* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method LCL_FILE_http->SET_URI
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_FILE_NAME                   TYPE        STRING
* | [--->] IV_TARGET_FOLDER               TYPE        STRING
* | [<-()] RV_URI                         TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD set_uri.
*      IMPORTING
*        !iv_file_name     TYPE string
*        !iv_target_folder TYPE string
*      RETURNING
*        VALUE(rv_uri)     TYPE string .

    " Sets the full URI for the file in the target system

    DATA lv_path TYPE string.

    CONCATENATE '/' iv_target_folder '/' iv_file_name INTO lv_path.
    CALL METHOD mr_client->create_abs_url
      EXPORTING
        path = lv_path
      RECEIVING
        url  = rv_uri.

  ENDMETHOD.
ENDCLASS.


* ======================================================================
* lcl_sample:
* Handles the processing according to the parameters set
* by the user on the selection screen of the report
* ======================================================================
CLASS lcl_sample DEFINITION FINAL.

  PUBLIC SECTION.

    METHODS main
      IMPORTING
        !iv_dest  TYPE rfcdest
        !iv_out   TYPE abap_bool
        !iv_multi TYPE abap_bool
        !iv_lsrc  TYPE string
        !iv_rsrc  TYPE string
        !iv_rfold TYPE string
        !iv_encr  TYPE abap_bool
        !iv_decr  TYPE abap_bool
        !iv_pse   TYPE ssfappl
        !iv_rec   TYPE certsubjct
      .

    METHODS process_outbound
      IMPORTING
        !iv_multi TYPE abap_bool
        !iv_lsrc  TYPE string
        !iv_rfold TYPE string
        !iv_encr  TYPE abap_bool
        !iv_pse   TYPE ssfappl
        !iv_rec   TYPE certsubjct
      .

    METHODS process_inbound
      IMPORTING
        !iv_rsrc TYPE string
        !iv_decr TYPE abap_bool
        !iv_pse  TYPE ssfappl
        !iv_rec  TYPE certsubjct
      .

    METHODS get_file_list
      IMPORTING
        !iv_multi    TYPE abap_bool
        !iv_lsrc     TYPE string
      EXPORTING
        !et_filename TYPE string_table
      .

  PRIVATE SECTION.

***************************************************************************
*** @CUSTOMER:
*** Use logical file names in order to prevent directory traversal.
*** The user only has the possibility to select the file name, but not
*** the directory on the application server.
*** If you want to have some flexibility in the names of the actual files,
*** customize your logical file names such that the name of the physical
*** file is used as (part of) the logical file name.
*** Otherwise, simply use hard-coded file names as well, and do not offer
*** the user the possibility to enter them.
***
*** Use transaction FILE to maintain logical paths and file names
***************************************************************************

    CONSTANTS: gc_logical_fname_inbound  TYPE fileintern VALUE 'ZSAMPLE_INBOUND',
               gc_logical_fname_outbound TYPE fileintern VALUE 'ZSAMPLE_OUTBOUND'.

    DATA: mo_file_http TYPE REF TO lcl_file_http.

ENDCLASS.

CLASS lcl_sample IMPLEMENTATION.

  METHOD main.
*      IMPORTING
*        !iv_dest  TYPE rfcdest
*        !iv_out   type abap_bool
*        !iv_multi TYPE abap_bool
*        !iv_lsrc  TYPE string
*        !iv_rsrc  TYPE string
*        !iv_rfold TYPE string
*        !iv_encr  TYPE abap_bool
*        !iv_decr  TYPE abap_bool
*        !iv_pse   TYPE ssfappl
*        !iv_rec   TYPE certsubjct
*      .


    TRY.
        CREATE OBJECT mo_file_http
          EXPORTING
            iv_rfc_dest = iv_dest.

      CATCH cx_dest_http_abap_special.
        MESSAGE e016(pg) WITH 'Error in http client creation' ' - processing terminated'.
        RETURN.
    ENDTRY.

    IF iv_out = abap_true.
      CALL METHOD me->process_outbound
        EXPORTING
          iv_multi = iv_multi
          iv_lsrc  = iv_lsrc
          iv_rfold = iv_rfold
          iv_encr  = iv_encr
          iv_pse   = iv_pse
          iv_rec   = iv_rec.
    ELSE.
      CALL METHOD me->process_inbound
        EXPORTING
          iv_rsrc = iv_rsrc
          iv_decr = iv_decr
          iv_pse  = iv_pse
          iv_rec  = iv_rec.
    ENDIF.

    WRITE: / 'Processing finished.'.

  ENDMETHOD.

  METHOD process_outbound.
*        !iv_multi TYPE abap_bool
*        !iv_lsrc  TYPE string
*        !iv_rfold TYPE string
*        !iv_encr  TYPE abap_bool
*        !iv_pse   TYPE ssfappl
*        !iv_rec   TYPE certsubjct

    " ---------------------------------------------------------
    " Read files from the application server,
    " encrypt them if requested,
    " and send them to the remote server
    " ---------------------------------------------------------

    DATA:
      lt_filename TYPE string_table,
      lr_file     TYPE REF TO lcl_file,
      lv_rc       TYPE sysubrc,
      lv_xstring  TYPE xstring,
      lv_bytes    TYPE i
      .

    FIELD-SYMBOLS:
                   <lv_filename> TYPE string.

    CALL METHOD get_file_list
      EXPORTING
        iv_multi    = iv_multi
        iv_lsrc     = iv_lsrc
      IMPORTING
        et_filename = lt_filename. " file names without path

    IF lt_filename IS INITIAL.
      WRITE: / 'No files in local source directory - nothing to be sent'.
      RETURN.
    ENDIF.


    LOOP AT lt_filename ASSIGNING <lv_filename>.

      CREATE OBJECT lr_file.

      " Load file from application server
      " Logical file name is checked inside load_from_applsrv
      CALL METHOD lr_file->load_from_applsrv
        EXPORTING
          iv_pathname = gc_logical_fname_outbound
          iv_filename = <lv_filename>
        RECEIVING
          rv_subrc    = lv_rc.

      IF lv_rc <> 0.
        WRITE: / 'Could not load file ', <lv_filename>, ' - skipping it'.
        CONTINUE.
      ENDIF.

      IF iv_encr = abap_true.
        TRY.
            CALL METHOD lr_file->encrypt
              EXPORTING
                iv_pse       = iv_pse
                iv_recipient = iv_rec.
          CATCH cx_crypto_error .
            WRITE: / 'Error in encryption - ' ,  ' processing terminated'.
            RETURN.
        ENDTRY.
        " use encrypted content for sending
        CALL METHOD lr_file->get_xstring
          EXPORTING
            iv_mode    = lcl_file=>gc_mode_encrypted
          IMPORTING
            ev_xstring = lv_xstring
            ev_length  = lv_bytes
            ev_subrc   = lv_rc.
      ELSE.
        " use original content for sending
        CALL METHOD lr_file->get_xstring
          EXPORTING
            iv_mode    = lcl_file=>gc_mode_orig
          IMPORTING
            ev_xstring = lv_xstring
            ev_length  = lv_bytes
            ev_subrc   = lv_rc.
      ENDIF.

      IF lv_rc <> 0.
        CONTINUE.
      ENDIF.

      CALL METHOD mo_file_http->send
        EXPORTING
          iv_target_folder = iv_rfold
          iv_file_name     = <lv_filename>
          iv_content_type  = lr_file->get_mimetype( )
          iv_content       = lv_xstring
          iv_bytes         = lv_bytes.

    ENDLOOP.

  ENDMETHOD.

  METHOD process_inbound.
*      IMPORTING
*        !iv_rsrc  TYPE string
*        !iv_decr  TYPE abap_bool
*        !iv_pse   TYPE ssfappl
*        !iv_rec   TYPE certsubjct

    " ---------------------------------------------------------
    " Retrieve file from the remote server,
    " decrypt it if requested,
    " and store it on the application server
    " ---------------------------------------------------------

    DATA:
      lr_file    TYPE REF TO lcl_file,
      lv_content TYPE xstring,
      lv_bytes   TYPE i,
      lv_rc      TYPE sysubrc,
      lv_mode    TYPE c.

    CALL METHOD mo_file_http->get
      EXPORTING
        iv_source_path = iv_rsrc
      IMPORTING
        ev_content     = lv_content
        ev_bytes       = lv_bytes
        ev_subrc       = lv_rc.

    IF lv_rc IS NOT INITIAL OR lv_bytes IS INITIAL.
      WRITE: / 'Remote file could not be retrieved.'.
      RETURN.
    ENDIF.

    CREATE OBJECT lr_file.
    CALL METHOD lr_file->create_from_xstring
      EXPORTING
        iv_xstring  = lv_content
        iv_pathname = iv_rsrc
        iv_bytes    = lv_bytes.

    IF iv_decr = abap_true.
      TRY.
          CALL METHOD lr_file->decrypt
            EXPORTING
              iv_pse       = iv_pse
              iv_recipient = iv_rec.
        CATCH cx_crypto_error .
          WRITE: / 'Error in decryption - ' ,  ' file will not be saved'.
          RETURN.
      ENDTRY.
      lv_mode = lcl_file=>gc_mode_decrypted.
    ELSE.
      lv_mode = lcl_file=>gc_mode_orig.
    ENDIF.

    CALL METHOD lr_file->save
      EXPORTING
        iv_pathname = gc_logical_fname_inbound
        iv_mode     = lv_mode.

  ENDMETHOD.


  METHOD get_file_list.
*      IMPORTING
*        !iv_multi    TYPE abap_bool
*        !iv_lsrc     TYPE string
*      EXPORTING
*        !et_filename TYPE string_table

    " -----------------------------------------------------------------------
    " Gets the list of file names (without path)
    " for the files that are to be processed
    " -----------------------------------------------------------------------

    DATA:
      lv_message  TYPE string,
      lv_flag     TYPE abap_bool,
      lv_dirname  TYPE epsdirnam,
      lt_dir_list TYPE TABLE OF epsfili,
      lv_filename TYPE string
      .

    FIELD-SYMBOLS:
      <ls_dir_list>        TYPE epsfili
      .

    CLEAR et_filename.
    IF iv_multi = abap_true.

      " Get the names of all usable files in the logical path

      " @CUSTOMER:
      " This function call gives us the physical path to the
      " logical file name - requires appropriate setup in
      " transaction FILE

      CALL FUNCTION 'FILE_GET_NAME'
        EXPORTING
          logical_filename = gc_logical_fname_outbound
        IMPORTING
          emergency_flag   = lv_flag
          file_name        = lv_dirname  " physical path
        EXCEPTIONS
          file_not_found   = 1
          OTHERS           = 2.

      IF sy-subrc <> 0 OR lv_flag IS NOT INITIAL.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
          INTO lv_message.
        WRITE: / lv_message.
        WRITE: / 'Logical path ', gc_logical_fname_outbound,  ' cannot be read - outbound processing cancelled.'.
        RETURN.
      ENDIF.

      CALL FUNCTION 'EPS_GET_DIRECTORY_LISTING'
        EXPORTING
          dir_name               = lv_dirname
        TABLES
          dir_list               = lt_dir_list " file names without path, plus size
        EXCEPTIONS
          invalid_eps_subdir     = 1
          sapgparam_failed       = 2
          build_directory_failed = 3
          no_authorization       = 4
          read_directory_failed  = 5
          too_many_read_errors   = 6
          empty_directory_list   = 7
          OTHERS                 = 8.

      IF sy-subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
           WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
           INTO lv_message.
        WRITE: / lv_message.
        WRITE: / 'Physical path for  ', gc_logical_fname_outbound,  ' cannot be accessed - outbound processing cancelled.'.
        RETURN.
      ENDIF.

      LOOP AT lt_dir_list ASSIGNING <ls_dir_list>.
        CHECK <ls_dir_list>-rc = 0 AND
              <ls_dir_list>-size > 0 AND
              <ls_dir_list>-name(4) <> 'core'.
        lv_filename = <ls_dir_list>-name.
        APPEND lv_filename TO et_filename.
      ENDLOOP.

    ELSE.

      " only one file (name entered by the user)
      APPEND iv_lsrc TO et_filename.

    ENDIF. " IF iv_multi = abap_true

  ENDMETHOD.

ENDCLASS.




* ==================================================================
* The report itself
* ==================================================================

" ------------------------------------------------------------------
" GLOBAL VARIABLES
" Mostly needed for handling screen fields (properties and content)
" ------------------------------------------------------------------
DATA: go_sample     TYPE REF TO lcl_sample ##NEEDED,
      gv_program    TYPE sy-repid ##NEEDED,
      gt_fieldvalue TYPE STANDARD TABLE OF rsselread ##NEEDED,
      gs_fieldvalue TYPE rsselread ##NEEDED,
      gv_encr       TYPE abap_bool ##NEEDED, " encrypt?
      gv_decr       TYPE abap_bool ##NEEDED, " decrypt?
      gv_rsrc       TYPE string ##NEEDED, " remote source file
      gv_lsrc       TYPE string ##NEEDED, " local source file
      gv_rfold      TYPE string ##NEEDED, " remote folder
      gv_multi      TYPE abap_bool ##NEEDED. "all files from folder?


*********************************************************************
*** @CUSTOMER:
*** Selections are mainly for testing purposes.
*** Depending on your use case you may eliminate
*** some - or even all - selection parameters
*** For example, if you always send the same file
*** to the same destination, you can hard-code all these parameters.
*********************************************************************

" ------------------------------------------------------------------
" SELECTION SCREEN
" ------------------------------------------------------------------
" Settings for both inbound and outbound processing
SELECTION-SCREEN: BEGIN OF BLOCK a01 WITH FRAME TITLE text-a01.              "General Settings
PARAMETERS: p_dest TYPE rfcdest MATCHCODE OBJECT esh_h_rfcdest_g OBLIGATORY. "RFC destination (as in SM59)
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN: BEGIN OF BLOCK a02 WITH FRAME TITLE text-a02.              "Encryption/Decryption
PARAMETERS: p_pse TYPE ssfappl MATCHCODE OBJECT f4strustssf.                 "SSF Application (PSE)
PARAMETERS: p_rec TYPE  certsubjct.                                          "Recipient (Cert. Subject)
SELECTION-SCREEN: END OF BLOCK a02.
SELECTION-SCREEN: END OF BLOCK a01.
SELECTION-SCREEN SKIP 1.

" Outbound processing only
PARAMETERS: p_out RADIOBUTTON GROUP m1 DEFAULT 'X'.                          "Outbound Processing 出站处理
SELECTION-SCREEN: BEGIN OF BLOCK b01 WITH FRAME.
SELECTION-SCREEN: BEGIN OF BLOCK b02 WITH FRAME TITLE text-b02.              "Selection Mode
PARAMETERS: p_single RADIOBUTTON GROUP g1 DEFAULT 'X',                       "Single file 单个选择文件
            p_lsrc   TYPE string,                                            "Local Source File 本地源文件
            p_multi  RADIOBUTTON GROUP g1.                                   "All Files from Folder 文件夹中的所有文件
SELECTION-SCREEN: END OF BLOCK b02.
PARAMETERS:
  p_rfold TYPE string LOWER CASE,                                            "Remote Target Folder 远程目标文件夹
  p_encr  AS CHECKBOX.                                                       "Encrypt before sending 发送前加密
SELECTION-SCREEN: END OF BLOCK b01.
SELECTION-SCREEN SKIP 1.

" Inbound processing only
PARAMETERS: p_in RADIOBUTTON GROUP m1.                                       "Inbound Processing 入站处理
SELECTION-SCREEN: BEGIN OF BLOCK c02 WITH FRAME.
PARAMETERS: p_rsrc TYPE string LOWER CASE,                                   "Remote Source File 远程源文件
            p_decr AS CHECKBOX.                                              "Decrypt before saving 保存前解密
SELECTION-SCREEN: END OF BLOCK c02.


INITIALIZATION.
  " ----------------------------------------------------------
  " @CUSTOMER:
  " You must not use this sample coding 'as is'
  " The program cannot be executed unless you make changes
  " to the coding you copied from the sample
  " ----------------------------------------------------------

*“您不能使用“按原样”的示例编码”
*“除非进行更改,否则无法执行该程序
*“复制到您从样本中复制的编码
*" ---------------------------------------------
  MESSAGE e016(pg) WITH '>>> This is only sample coding <<< ' '>>> Please adjust it to your needs <<<'.


" ------------------------------------------------------------------
" SCREEN EVENTS
" ------------------------------------------------------------------

" ------------------------------------------------------------
" Control the selection screen
" ------------------------------------------------------------

AT SELECTION-SCREEN OUTPUT.

  " disable irrelevant fields, depending on outbound/inbound direction
  PERFORM toggle_fields.


AT SELECTION-SCREEN ON RADIOBUTTON GROUP m1.

  " When user toggles between outbound and inbound:
  " 1) get content of fields for both directions
  " 2) disable fields for the direction that has not been selected
  " 3) preserve existing field content such that it is still available
  "    if the user toggles back
*“当用户在出站和入站之间切换时:
*“1)获取两个方向的字段内容
*“2)禁用未选择方向的字段
*“3)保留现有字段内容,使其仍然可用
*“如果用户切换回
  PERFORM get_field_content.
  PERFORM toggle_fields.
  PERFORM set_field_content.


  " ----------------------------------------------------------
  " Check input consistency
  " ----------------------------------------------------------

AT SELECTION-SCREEN.

  IF p_out IS NOT INITIAL AND  p_rfold IS INITIAL.
    MESSAGE e016(pg) WITH 'Please specify ' 'target folder for' 'outbound processing.'.
  ENDIF.

  IF p_out IS INITIAL AND p_rsrc IS INITIAL .
    MESSAGE e016(pg) WITH 'Please specify' 'source file for' 'inbound processing.'.
  ENDIF.

  IF ( p_pse IS INITIAL OR p_rec IS INITIAL ) AND
       ( ( p_out IS NOT INITIAL AND p_encr IS NOT INITIAL ) OR
         ( p_out IS INITIAL AND p_decr IS NOT INITIAL )   ).
    MESSAGE e016(pg) WITH 'Please specify' ' PSE and recipient for ' ' de-/encryption'.
  ENDIF.


  " ----------------------------------------------------------
  " Trigger send/receive functionality
  " ----------------------------------------------------------

START-OF-SELECTION.

  CREATE OBJECT go_sample.

  CALL METHOD go_sample->main
    EXPORTING
      iv_dest  = p_dest
      iv_out   = p_out
      iv_multi = p_multi
      iv_lsrc  = p_lsrc
      iv_rsrc  = p_rsrc
      iv_rfold = p_rfold
      iv_encr  = p_encr
      iv_decr  = p_decr
      iv_pse   = p_pse
      iv_rec   = p_rec.


*&---------------------------------------------------------------------*
*&      Form  TOGGLE_FIELDS
*&---------------------------------------------------------------------*
*       Enable or disable fields depending on selection of
*       outbound / inbound processing
*----------------------------------------------------------------------*
FORM toggle_fields .
  LOOP AT SCREEN.
    IF p_out IS NOT INITIAL.
      IF screen-name = 'P_RSRC' OR
         screen-name = 'P_DECR'.
        screen-input = 0.
      ELSE.
        IF screen-name = 'P_SINGLE' OR
         screen-name = 'P_MULTI' OR
         screen-name = 'P_RFOLD' OR
         screen-name = 'P_ENCR'.
          screen-input = 1.
        ENDIF.
        IF screen-name = 'P_LSRC'. "name of single file
          IF p_single IS NOT INITIAL.
            screen-input = 1.
          ELSE.
            screen-input = 0.
          ENDIF.
        ENDIF.

      ENDIF.
      MODIFY SCREEN.
    ELSE.
      IF screen-name = 'P_RSRC' OR
         screen-name = 'P_DECR'.
        screen-input = 1.
      ELSEIF screen-name = 'P_SINGLE' OR
         screen-name = 'P_MULTI' OR
         screen-name = 'P_LSRC' OR
         screen-name = 'P_RFOLD' OR
         screen-name = 'P_ENCR'.
        screen-input = 0.
      ENDIF.
      MODIFY SCREEN.
    ENDIF.
  ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  GET_FIELD_CONTENT
*&---------------------------------------------------------------------*
*   Get field content from selection screen such that
*   it can be preserved when user toggles between
*   outbound and inbound
*----------------------------------------------------------------------*
FORM get_field_content .

  gv_program = sy-repid.
  CLEAR gt_fieldvalue.

  " fields for outbound processing
  gs_fieldvalue-kind = 'P'. "selection parameter
  gs_fieldvalue-name = 'P_MULTI'.
  APPEND gs_fieldvalue TO gt_fieldvalue.
  gs_fieldvalue-name = 'P_LSRC'.
  APPEND gs_fieldvalue TO gt_fieldvalue.
  gs_fieldvalue-name = 'P_RFOLD'.
  APPEND gs_fieldvalue TO gt_fieldvalue.
  gs_fieldvalue-name = 'P_ENCR'.
  APPEND gs_fieldvalue TO gt_fieldvalue.

  " fields for inbound processing
  gs_fieldvalue-name = 'P_RSRC'.
  APPEND gs_fieldvalue TO gt_fieldvalue.
  gs_fieldvalue-name = 'P_DECR'.
  APPEND gs_fieldvalue TO gt_fieldvalue.

  CALL FUNCTION 'RS_SELECTIONSCREEN_READ'
    EXPORTING
      program     = gv_program
    TABLES
      fieldvalues = gt_fieldvalue.

  " outbound
  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_MULTI'.
  IF sy-subrc = 0.
    gv_multi = gs_fieldvalue-fieldvalue.
  ENDIF.
  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_LSRC'.
  IF sy-subrc = 0.
    gv_lsrc = gs_fieldvalue-fieldvalue.
  ENDIF.

  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_RFOLD'.
  IF sy-subrc = 0.
    gv_rfold = gs_fieldvalue-fieldvalue.
  ENDIF.
  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_ENCR'.
  IF sy-subrc = 0.
    gv_encr = gs_fieldvalue-fieldvalue.
  ENDIF.

  " inbound
  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_RSRC'.
  IF sy-subrc = 0.
    gv_rsrc = gs_fieldvalue-fieldvalue.
  ENDIF.
  READ TABLE gt_fieldvalue INTO gs_fieldvalue WITH KEY name = 'P_DECR'.
  IF sy-subrc = 0.
    gv_decr = gs_fieldvalue-fieldvalue.
  ENDIF.

ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  SET_FIELD_CONTENT
*&---------------------------------------------------------------------*
*       Set field content to previous values (after user
*       has toggled between outbound and inbound)
*----------------------------------------------------------------------*
FORM set_field_content .

  " outbound
  p_rfold = gv_rfold.
  p_multi = gv_multi.
  p_lsrc = gv_lsrc.
  p_encr = gv_encr.

  " inbound
  p_rsrc = gv_rsrc.
  p_decr = gv_decr.

ENDFORM.

风口的猪会飞
13 声望20 粉丝

ABAP PI 开发 这个世界没有神,如果有那也是别人口中的神而已!


引用和评论

0 条评论