症状
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 或抉择任何其余名称。
- 在编辑器中,抉择 Utilities -> More Utilities -> Upload/Download 并将附件(ZSAMPLE_CRYPT_TRANSFER_FILE.txt)上传 到该程序中。
- 激活程序。
- 抉择 Goto -> Text Elements 为每个抉择参数和抉择屏幕的每个块定义文本。
您会在抉择文本的选项卡上找到一些条目:这些条目是在程序激活期间依据抉择参数主动生成的,当初您只需填写文本。通过双击程序中块题目的文本符号 text-<xyz>
为文本符号创立条目。适当的文本蕴含在示例编码中,作为每个抉择参数或块题目旁边的正文,您能够简略地将它们从那里复制到抉择文本或文本符号中。
提醒:您将在示例编码的开端找到抉择屏幕的定义。
- 激活文本。
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.