Skip to Content
Author's profile photo David Halitsky

Warning! Toxic Code That You May Need Some Day

Your infrastructure team is having difficulty connecting to the SAP Content Server they’ve just installed.

Therefore, you can’t switch your SAPOffice attachments over from SOFFDB to SOFFHTTP yet. 

So therefore, you can’t pass URL’s for graphic attachments to the load method of cl_gui_picture using cl_bds_document_set->get_with_url (because there are no URL’s for these attachments?

How do you load cl_gui_picture from your physical contents stored in SOFFCONT1?

Here’s one way that’s really toxic, but should work.  Will report back to this blog post whether it does or not.

 

wa_objectid-objkey  = viqmel-qmnum.   ” i.e. – a PM notification number

wa_objectid-objtype = ‘BUS2038’.

CALL FUNCTION ‘BAPI_REL_GETRELATIONS’

  EXPORTING

    OBJECTID              = wa_objectid

    RECURSIONLEVEL        = 1

  IMPORTING

    RETURN                = v_rtrn

  TABLES

    LISTOFRELATIONS       = i_listrel.

v_cntr = 0.

v_nmbr = 0.

LOOP AT i_listrel into wa_listrel.

  IF wa_listrel-reltype <> ‘ATTA’.

    CONTINUE.

  ENDIF.

  APPEND wa_listrel TO i_listrel2.

ENDLOOP.

* make sure you have as many instances of cl_gui_picture as you

* need and as many custom containers on the screen as you need

LOOP AT i_listrel2 INTO wa_listrel.

  v_objtype = wa_listrel-objtype_b.

  v_objkey  = wa_listrel-objkey_b.

      swc_create_object v_obj1 v_objtype v_objkey.

      swc_get_property  v_obj1 ‘Description’ v_objdes.

      swc_get_property  v_obj1 ‘FileExtension’ v_fileext.

      wa_atts-name      = v_objdes.

      wa_atts-ext       = v_fileext.

      APPEND wa_atts TO i_atts.

*     1) get the actual SOFFCONT1 content by driving into SOFFPHF

*        using v_objdes+v_filext (concatenated)

*     2) manipulate the SOFFCONT1 content into a format/type

*        acceptable to the piece of code shown below from

*        SAP program BSP_UPDATE_MIMEREPOS

*     3) use what you need from the BSP_UPDATE_MIMEREPOS code below to store

*        to store a copy of the content in SAP’s MIME repos     

*         (this code includes creating a URL, of course)

*     4) pass the URL of the newly created “MIME” to the

*        load method of your picture control

ENDLOOP.

* here’s the part of bsp_update_mimerepos that you’ll need to steal code from to create a temporary copy of your graphic in the MIME repository; note that instead of uploading a graphic from a drive, you’re creating it from the contents in SOFFCONT1.

 

      CALL METHOD cl_gui_frontend_services=>gui_upload

        EXPORTING

          filename                = l_filename

          filetype                = ‘BIN’

          read_by_line            = ‘X’

        IMPORTING

          filelength              = l_filelength

        CHANGING

          data_tab                = itab_files

        EXCEPTIONS

          file_open_error         = 1

          file_read_error         = 2

          no_batch                = 3

          gui_refuse_filetransfer = 4

          invalid_type            = 5

          no_authority            = 6

          unknown_error           = 7

          bad_data_format         = 8

          header_not_allowed      = 9

          separator_not_allowed   = 10

          header_too_long         = 11

          unknown_dp_error        = 12

          access_denied           = 13

          dp_out_of_memory        = 14

          disk_full               = 15

          dp_timeout              = 16

          not_supported_by_gui    = 17

          error_no_gui            = 18

          OTHERS                  = 19.

 

      IF sy-subrc <> 0.

        WRITE: /(6) icon_red_light AS ICON, (55) text-006, l_filename.

*       Fehler beim Upload der Datei!

        CONTINUE.

      ENDIF.

 

      CLEAR: l_content.

 

* — we need the file content as xstring

      LOOP AT itab_files INTO wa_files.

        CONCATENATE l_content wa_files INTO l_content IN BYTE MODE.

      ENDLOOP.

 

* — cut according to filelength

      l_content = l_content(l_filelength).

 

      CLEAR: x, y, l_url.

 

      IF l_url IS INITIAL.

        IF onefile = ‘X’.

          CLEAR: x, y.

          DO.

            FIND ‘\’ IN wa_file_table-filename+x MATCH OFFSET y.

            IF sy-subrc = 0.

              x = x + y + 1.

            ELSE.

              EXIT.

            ENDIF.

          ENDDO.

          CONCATENATE mimepath wa_file_table-filename+x INTO l_url.

          CLEAR: x, y.

        ELSE.

          CONCATENATE mimepath wa_file_table-filename INTO l_url.

        ENDIF.

      ENDIF.

 

* — to be consistent with windows pathes

      TRANSLATE l_url USING ‘\/’.

 

* — now compare the LOIOs of local files with MR information

* — + if file is missing, we will create it with given LOIO

* — + if file is present, but LOIOs differ:

* —   ++ if checkbox ovwrloio is checked, we will delete MR file

* —   ++ otherwise we will only write a message

      IF NOT itab_loio IS INITIAL.

*        DATA: l_url_folder LIKE l_url.

*        LOOP AT itab_loio INTO wa_file_loio WHERE is_folder IS INITIAL.

        DATA: abs_name LIKE wa_file_table-filename.

        CONCATENATE l_rootdir ‘\’ wa_file_table-filename INTO abs_name.

        READ TABLE itab_loio WITH KEY name = abs_name INTO wa_file_loio.

        IF sy-subrc <> 0.

          ULINE.

          FORMAT COLOR COL_NEGATIVE ON.

          WRITE: /(6) icon_loio_class AS ICON, (255) text-033.

*         LOIO zu File konnte nicht ermttelt werden

          WRITE: /(6) icon_red_light AS ICON, (255) text-034.

          WRITE: /(6) icon_red_light AS ICON, (255) abs_name.

*         Datei wird nicht angelegt!

          FORMAT COLOR COL_NEGATIVE OFF.

          ULINE.

          CONTINUE.

        ENDIF.

*          CONCATENATE mimepath wa_file_loio-name INTO l_url.

        CLEAR: is_folder.

 

* — to be consistent with windows pathes

        TRANSLATE l_url USING ‘\/’.

 

        CALL METHOD o_mr_api->get

          EXPORTING

            i_url              = l_url

          IMPORTING

            e_is_folder        = is_folder

            e_content          = l_current

            e_loio             = l_loio

          EXCEPTIONS

            parameter_missing  = 1

            error_occured      = 2

            not_found          = 3

            permission_failure = 4

            OTHERS             = 5.

*

        IF sy-subrc <> 0.

          CASE sy-subrc.

            WHEN 3.              “* — mime not found -> go on…

              CLEAR l_current.

            WHEN 4.

              WRITE: /(6) icon_red_light AS ICON, (55) text-007, l_url.

*             Keine Leseberechtigung an Mime-Objekt

              CONTINUE.

            WHEN OTHERS.

              WRITE: /(6) icon_red_light AS ICON, (55) text-008, l_url.

*             Fehler beim Lesen des Mime-Objektes

              CONTINUE.

          ENDCASE.

        ELSE.

          IF wa_file_loio-loio NE l_loio AND withloio = ‘X’.

            WRITE: /(6) icon_yellow_light AS ICON, (55) text-019, l_url.

*           LOIOs unterschiedlich

            IF ovwrloio EQ ‘X’.

* — delete MR file, if LOIOs differ

              CALL METHOD o_mr_api->delete

                EXPORTING

                  i_url              = l_url

                  i_delete_children  = ”

                  i_check_authority  = ‘X’

*                 I_CORR_NUMBER      =

                EXCEPTIONS

                  parameter_missing  = 1

                  error_occured      = 2

                  cancelled          = 3

                  permission_failure = 4

                  not_found          = 5

                  OTHERS             = 6.

 

              IF sy-subrc <> 0.

                CASE sy-subrc.

                  WHEN 4.

                    WRITE: /(6) icon_red_light AS ICON, (55) text-023, l_url.

*                   Keine Berechtigung zum Löschen der Datei

                    CONTINUE.

                  WHEN OTHERS.

                    WRITE: /(6) icon_red_light AS ICON, (55) text-022, l_url.

*                   Fehler beim Löschen der Datei

                    CONTINUE.

                ENDCASE.

              ELSE.

                WRITE: /(6) icon_loio_class AS ICON, (55) text-024, l_url.

*               Datei wird neu angelegt (LOIO-Abgleich)

                CLEAR l_current.

              ENDIF.

 

            ENDIF.  “ovwrloio

          ENDIF.  “wa_file_loio-loio NE l_loio and withloio = ‘X

        ENDIF.  “sy-subrc

      ENDIF.  “itab_loio initial

 

* — new

      IF withloio IS INITIAL.

* — to be consistent with windows pathes

        TRANSLATE l_url USING ‘\/’.

 

        CALL METHOD o_mr_api->get

          EXPORTING

            i_url              = l_url

          IMPORTING

            e_is_folder        = is_folder

            e_content          = l_current

            e_loio             = l_loio

          EXCEPTIONS

            parameter_missing  = 1

            error_occured      = 2

            not_found          = 3

            permission_failure = 4

            OTHERS             = 5.

*

        IF sy-subrc <> 0.

          CASE sy-subrc.

            WHEN 3.              “* — mime not found -> go on…

              CLEAR l_current.

            WHEN 4.

              WRITE: /(6) icon_red_light AS ICON, (55) text-007, l_url.

*             Keine Leseberechtigung an Mime-Objekt

              CONTINUE.

            WHEN OTHERS.

              WRITE: /(6) icon_red_light AS ICON, (55) text-008, l_url.

*             Fehler beim Lesen des Mime-Objektes

              CONTINUE.

          ENDCASE.

        ENDIF.

      ENDIF.

* — end new

 

* — check, if this is a css-file

* — css -> convert to ascii, exclude timestamp and compare ascii

      DATA: l_oldascii   TYPE string.

      DATA: l_newascii   TYPE string.

      DATA: conv         TYPE REF TO cl_abap_conv_in_ce.

      DATA: length       TYPE i.

      DATA: new_offset   TYPE i, old_offset TYPE i.

 

      CLEAR: new_offset, old_offset, l_newascii, l_oldascii.

 

      length = STRLEN( l_url ) – 4.

      IF length > 0 AND l_url+length CS ‘.css’.

 

* — NEW: exclude timestamp (17B) and compare xstring…

        IF XSTRLEN( l_content ) > 17 AND XSTRLEN( l_current ) > 17.

          IF l_current+17 = l_content+17.

            CONTINUE.

          ENDIF.

        ENDIF.

*        conv = cl_abap_conv_in_ce=>create( input = l_content ).

*        conv->read( IMPORTING data = l_newascii len = length ).

*

*        IF NOT l_current IS INITIAL.

*          conv = cl_abap_conv_in_ce=>create( input = l_current ).

*          conv->read( IMPORTING data = l_oldascii len = length ).

*        ENDIF.

*

** — identify timestamp and the corresponding offset

*        IF STRLEN( l_newascii ) > 24 AND l_newascii(2) = ‘/*’ AND l_newascii+2(22) CS ‘*/’.

*          new_offset = sy-fdpos + 4.

*        ENDIF.

*        IF STRLEN( l_oldascii ) > 24 AND l_oldascii(2) = ‘/*’ AND l_oldascii+2(22) CS ‘*/’.

*          old_offset = sy-fdpos + 4.

*        ENDIF.

*

** — compare ascii

*        IF l_oldascii+old_offset = l_newascii+new_offset.

*          CONTINUE.

*        ENDIF.

*

      ELSE.

* — compare binary

        IF l_current = l_content.

          CONTINUE.

        ENDIF.

      ENDIF.

 

* — update only if content has changed

* — if no LOIO was included, the put method will

* — create a new one

      CALL METHOD o_mr_api->put

        EXPORTING

          i_url                     = l_url

          i_content                 = l_content

          i_suppress_package_dialog = ‘X’

          i_new_loio                = wa_file_loio-loio

        EXCEPTIONS

          parameter_missing         = 1

          error_occured             = 2

          cancelled                 = 3

          permission_failure        = 4

          data_inconsistency        = 5

          OTHERS                    = 6.

**************************************************************************

Like I said – really really toxic – but what are you gonna do ?

************************************************************************** 

Assigned Tags

      8 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      Well, I was only off a litlle bit. Turns out that the type of the line of the table that comes back from SDOK_PHIO_LOAD_CONTENT is not compatible with the requirement to concatenate the line into an xstring (which is what BSP_UPDATE_MIMEREPOS wants to do. So instead, we use SO_OBJECT_DOWNLOAD to put the attachment to a file on disk, and then pass the path and name of this file to the load method of the picture control.

      The complete code (for a test of one attachment is as follows:

      CALL FUNCTION 'BAPI_REL_GETRELATIONS'
      EXPORTING
      * this is 'BUS2038' plus qmnum (notification number)
      objectid = gs_objectid
      recursionlevel = 1
      IMPORTING
      return = v_rtrn
      TABLES
      listofrelations = i_listrel.

      LOOP AT i_listrel INTO gs_listrel
      WHERE ( reltype = 'ATTA' ).
      gd_objtype = gs_listrel-objtype_b.
      gd_objkey = gs_listrel-objkey_b.
      gd_objkey2 = gs_listrel-objkey_b.

      EXIT. " simply take first attachment
      ENDLOOP.

      swc_create_object gd_obj1 gd_objtype gd_objkey.
      swc_get_property gd_obj1 'Description' gd_objdes.
      swc_get_property gd_obj1 'FileExtension' gd_fileext.

      WRITE: / gd_obj1-header, gd_obj1-type, gd_obj1-handle,
      gd_objdes,
      gd_fileext.

      CONCATENATE gd_objdes gd_fileext INTO v_file_name SEPARATED BY '.'.

      SELECT
      SINGLE phio_id
      INTO v_phio_id
      FROM soffphf
      WHERE file_name = v_file_name.

      PHIO_OBJECT-class = 'SOFFPHIO'.
      PHIO_OBJECT-objid = v_phio_id.

      SELECT
      SINGLE phio_id
      INTO v_phio_id
      FROM soffphf
      WHERE file_name = v_file_name.

      PHIO_OBJECT-class = 'SOFFPHIO'.
      PHIO_OBJECT-objid = v_phio_id.

      CALL FUNCTION 'SDOK_PHIO_LOAD_CONTENT'
      EXPORTING
      OBJECT_ID = PHIO_OBJECT
      TEXT_AS_STREAM = 'X'
      TABLES
      FILE_ACCESS_INFO = FILE_ACCESS_INFO
      FILE_CONTENT_ASCII = CONT_ASCII
      FILE_CONTENT_BINARY = CONT_BIN

      EXCEPTIONS
      NOT_EXISTING = 105
      NOT_AUTHORIZED = 1000
      NO_CONTENT = 105
      BAD_STORAGE_TYPE = 103
      OTHERS = 1000.

      READ TABLE FILE_ACCESS_INFO INDEX 1.
      IF SY-SUBRC <> 0.
      RAISE X_ERROR.
      ENDIF.
      FILESIZE = FILE_ACCESS_INFO-FILE_SIZE.

      PERFORM TABLE_COPY
      TABLES CONT_BIN
      solixtab "UNICODE 6.10
      CHANGING RCODE.

      IF RCODE NE 0.
      RAISE X_ERROR.
      ENDIF.

      CALL FUNCTION 'SO_SOLIXTAB_TO_SOLITAB' "UNICODE 6.10
      EXPORTING "UNICODE 6.10
      IP_SOLIXTAB = solixtab[] "UNICODE 6.10
      IMPORTING "UNICODE 6.10
      EP_SOLITAB = objcont[]. "UNICODE 6.10

      * * Correct table objcont
      check filesize ne '000000000000'. "Hack because of bug in KPro
      DESCRIBE FIELD WA_OBJCONT LENGTH LEN
      in character mode. "TR UNICODE
      data rest type i. "note 833448 >>
      rest = filesize mod len.
      if rest = 0.
      RIGHT_LINES = FILESIZE DIV LEN.
      else.
      RIGHT_LINES = ( FILESIZE DIV LEN ) + 1.
      endif. "note 833448 <<
      DEL_INDEX = RIGHT_LINES + 1.
      SIGNS_OF_LAST_LINE = FILESIZE MOD LEN.
      * * Delete superfluous lines
      DO.
      DELETE OBJCONT INDEX DEL_INDEX.
      IF SY-SUBRC NE 0.
      EXIT.
      ENDIF.
      ENDDO.
      * * Delete superfluous signs in last line
      if signs_of_last_line > 0. "note 833448 >>
      READ TABLE OBJCONT INDEX RIGHT_LINES INTO WA_OBJCONT.
      WA_OBJCONT+SIGNS_OF_LAST_LINE = SPACE.
      MODIFY OBJCONT INDEX RIGHT_LINES FROM WA_OBJCONT.
      endif. "note 833448 <<

      BIN_FILESIZE = filesize.
      CONCATENATE 'G:\160_PM_Prototype\070_Dev\'
      v_file_name
      INTO path_and_file.

      CALL FUNCTION 'SO_OBJECT_DOWNLOAD'
      EXPORTING
      BIN_FILESIZE = bin_FILESIZE
      DEFAULT_FILENAME = ' '
      FILETYPE = 'BIN'
      PATH_AND_FILE = path_and_file
      EXTCT = ' '
      NO_DIALOG = 'X'
      * IMPORTING
      * FILELENGTH =
      * F_CANCELLED =
      * ACT_FILETYPE =
      * ACT_FILENAME =
      TABLES
      OBJCONT = objcont
      EXCEPTIONS
      FILE_WRITE_ERROR = 1
      INVALID_TYPE = 2
      X_ERROR = 3
      KPRO_ERROR = 4
      OTHERS = 5.

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      Here it is:

      FORM TABLE_COPY TABLES   SOURCE_TAB
                               TARGET_TAB
                      CHANGING P_RCODE.

      DATA: AUX_TAB LIKE SOLI OCCURS 10.

      * * Init
        REFRESH TARGET_TAB.
      * * Compress table
        CALL FUNCTION 'TABLE_COMPRESS'
      *        IMPORTING
      *             COMPRESSED_SIZE =
             TABLES
                  IN              = SOURCE_TAB
                  OUT             = AUX_TAB
             EXCEPTIONS
                  COMPRESS_ERROR  = 1
                  OTHERS          = 2
                  .
        P_RCODE = SY-SUBRC.
        CASE P_RCODE.
          WHEN 0.
      *     * OK
          WHEN OTHERS.
            P_RCODE = 1000.
            EXIT.
        ENDCASE.
      * * Decompress table
        CALL FUNCTION 'TABLE_DECOMPRESS'
             TABLES
                  IN                   = AUX_TAB
                  OUT                  = TARGET_TAB
             EXCEPTIONS
                  COMPRESS_ERROR       = 1
                  TABLE_NOT_COMPRESSED = 2
                  OTHERS               = 3.
        REFRESH AUX_TAB.
        P_RCODE = SY-SUBRC.
        CASE P_RCODE.
          WHEN 0.
      *     * OK
          WHEN 2.
      *     * OK
            P_RCODE = 0.
          WHEN OTHERS.
            P_RCODE = 1000.
            EXIT.
        ENDCASE.

      ENDFORM.                               " TABLE_COPY

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      be sure to use the function SO_ATTACHMENT_LIST_READ and follow-on functions to get your content.  (See program SAPMSSOM.)  The code as given works, but there's no way to index file-name in SOFFPHF, so a full-table scan will be invoked by this select:

        SELECT
        SINGLE phio_id
          INTO v_phio_id
          FROM soffphf
         WHERE file_name = v_file_name.

      This select was just a cheat to get something working because the pressure from global HQ for a demo has been so intense ...

      Also, please recall again that all this code can be replaced by one line:

      call method cl_bds_document_set->get_with_url

      once you have a HTTP content server working (SAP's or a third-party's.)

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      When BAPI_REL_GETRELATIONS returns an object key for object type MESSAGE like:

      FOL23000000000004EXT32000000001320         

      you can take this value directly into SRGBTBREL using the secondary index on INSTID_B.  The returned row will give you the PHIO_ID as
      the column BRELGUID:

      46AB6A696021005A020000000A2A0866

      And this, of course, is also the PHIO_ID that you have to use to go into SOFFCONT1 to pick up the binary for your graphic attachment.

      This method is not only fail-safe (the PHIO_ID is unique per attachment), but also relies on indexed reads all the way through.

      Thanks again to aRS for providing the critical "intersection" table SRGBTBREL.

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      SRGBTBREL-BREELGUID is not the end of the story ... you have to perform a subtraction of 4 on the hex in positions 5-7 (offset 0) of srgbtbrel-brelguid in order to get the correct phio_id in SOFFCONT1 (and SOFFPHIO and SOFFPHF).

      Here are three examples:

      [code]
                1         2         3
      01234567890123456789012345678901
           |||
      46AC9DEB9ABF0075000000000A2A0866  SRGBTBREL
      46AC9DE79ABF0075000000000A2A0866  SOFFCONT1
           |||
      46AC9DF79ABF0075000000000A2A0866  SRGBTBREL
      46AC9DF39ABF0075000000000A2A0866  SOFFCONT1
           |||     
      46AC9E039ABF0075000000000A2A0866  SRGBTBREL 
      46AC9DFF9ABF0075000000000A2A0866  SOFFCONT1

      [/code]

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      And an equally special thanks to aRS over in ABAP general

      to a forum post with the chart in courier

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      BAPI_REL_GETRELATIONS returns:

      *RELTYPE     C     4      URL
      *RELATIONID     C     22      
      *UTCTIME     P     8       20070729190750
      *LOG_SYSTEM     C     10      BFSD030
      *OBJKEY_A     C     70      000200266362
      *OBJTYPE_A     C     10      BUS2038
      *LOGSYS_A     C     10      
      *LEVEL_A     N     2      00
      *ROLETYPE_A     C     10      APPLOBJ
      *ROLEID_A     C     22      
      *UTCTIME_A     P     8                    0
      *OBJKEY_B     C     70      FOL23000000000004URL32000000000033
      *OBJTYPE_B     C     10      MESSAGE
      *LOGSYS_B     C     10      
      *LEVEL_B     N     2      00
      *ROLETYPE_B     C     10      WEB_SITE
      *ROLEID_B     C     22      
      *UTCTIME_B     P     8                    0

      Then objkey_b returns this from srgbtbrel:

      *CLIENT      030
      *BRELGUID    46ACE1CFDD1B0059000000000A2A0866
      *RELTYPE     URL
      *INSTID A    000200266362
      *TYPEID A    BUS2038
      *CATID A     BO
      *INSTID B    FOL23000000000004URL32000000000033
      *TYPEID B    MESSAGE
      *CATID B     BO
      *LOGSYS A
      *ARCH A
      *LOGSYS B
      *ARCH B
      *UTCTIME     20,070,729,190,750
      *HOMESYS

      But where do I get the actual HTTP url for the attachment ?????

      Thanks for whatever help you can provide.
      djh

      Author's profile photo David Halitsky
      David Halitsky
      Blog Post Author
      On old systems (non-BDS, non-ContentServer), SO_OBJECT_READ can (must?) be used to get the LOIO_ID of an "EXT" (non-URL) attachment so that you can then take the LOIO_ID into SOFFPHIO to get the PHIO_ID to take into SOFFCONT1 when you call SDOK_PHIO_LOAD_CONTENT.

      This is just like using SO_DOCUMENT_READ_API1 to get the actual URL when BAPI_REL_GETRELATIONS returns a reltype of "URL".

      The only difference is that when BAPI_REL_GETRELATIONS returns a reltype of ATTA, you pass the first 17 bytes of objkey_b as fol_id to SO_OBJECT_READ and the second 17 bytes of objkey_b as doc_id to SO_OBJECT_READ.

      See "program" SAPLSO32 and the forms/function modules therein.