症状
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 processingSELECTION-SCREEN: BEGIN OF BLOCK a01 WITH FRAME TITLE text-a01. "General SettingsPARAMETERS: 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/DecryptionPARAMETERS: 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 onlyPARAMETERS: 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 ModePARAMETERS: 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 onlyPARAMETERS: 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.