关于abap:sap官方note-关于sftp的发送接收源代码

72次阅读

共计 37737 个字符,预计需要花费 95 分钟才能阅读完成。

症状
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.

正文完
 0