Merged in default - still have lots of failing tests, but can't fix that until Volker specifies whatever it was he was supposed to specify here, the thread has definitely been lost. Again.

doxygen_doc
commit 4429fa0292

@ -70,6 +70,10 @@ $(SRCROOT)/../asn.1/PString.c
$(SRCROOT)/../asn.1/PString.h
$(SRCROOT)/../asn.1/PrintableString.c
$(SRCROOT)/../asn.1/PrintableString.h
$(SRCROOT)/../asn.1/Rating.c
$(SRCROOT)/../asn.1/Rating.h
$(SRCROOT)/../asn.1/ReceiverRating.c
$(SRCROOT)/../asn.1/ReceiverRating.h
$(SRCROOT)/../asn.1/Rollback.c
$(SRCROOT)/../asn.1/Rollback.h
$(SRCROOT)/../asn.1/Sync.c

@ -171,8 +171,8 @@
431F04B722733A7E00CCE960 /* key_reset.h in Headers */ = {isa = PBXBuildFile; fileRef = 431F04B222733A7E00CCE960 /* key_reset.h */; };
432713B023A10B07007EAD4A /* GroupKeysForNewMember.c in Sources */ = {isa = PBXBuildFile; fileRef = 432713AF23A10B07007EAD4A /* GroupKeysForNewMember.c */; };
432714AB23A10B3B007EAD4A /* GroupKeysUpdate.c in Sources */ = {isa = PBXBuildFile; fileRef = 432714AA23A10B3B007EAD4A /* GroupKeysUpdate.c */; };
43370833203C075A004E6547 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 4337082D203C075A004E6547 /* sqlite3.c */; };
43370834203C075A004E6547 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 43370832203C075A004E6547 /* sqlite3.h */; };
436084242539A3B1005D56A7 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 436084222539A3B0005D56A7 /* sqlite3.c */; };
436084252539A3B1005D56A7 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 436084232539A3B1005D56A7 /* sqlite3.h */; };
4378C79123D1AF1700D1AF3F /* ElectGroupKeyResetLeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 4378C78B23D1AF1700D1AF3F /* ElectGroupKeyResetLeader.h */; };
4378C79223D1AF1700D1AF3F /* ElectGroupKeyResetLeader.c in Sources */ = {isa = PBXBuildFile; fileRef = 4378C79023D1AF1700D1AF3F /* ElectGroupKeyResetLeader.c */; };
438C43B52167752C00C7425B /* labeled_int_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 438C43AF2167752C00C7425B /* labeled_int_list.h */; };
@ -429,8 +429,8 @@
431F04B222733A7E00CCE960 /* key_reset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = key_reset.h; path = ../src/key_reset.h; sourceTree = "<group>"; };
432713AF23A10B07007EAD4A /* GroupKeysForNewMember.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GroupKeysForNewMember.c; path = ../asn.1/GroupKeysForNewMember.c; sourceTree = "<group>"; };
432714AA23A10B3B007EAD4A /* GroupKeysUpdate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GroupKeysUpdate.c; path = ../asn.1/GroupKeysUpdate.c; sourceTree = "<group>"; };
4337082D203C075A004E6547 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3.c; path = ../src/sqlite3.c; sourceTree = "<group>"; };
43370832203C075A004E6547 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = ../src/sqlite3.h; sourceTree = "<group>"; };
436084222539A3B0005D56A7 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3.c; path = ../../sqlite/sqlite3.c; sourceTree = "<group>"; };
436084232539A3B1005D56A7 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = ../../sqlite/sqlite3.h; sourceTree = "<group>"; };
4378C78B23D1AF1700D1AF3F /* ElectGroupKeyResetLeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ElectGroupKeyResetLeader.h; path = ../asn.1/ElectGroupKeyResetLeader.h; sourceTree = "<group>"; };
4378C79023D1AF1700D1AF3F /* ElectGroupKeyResetLeader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ElectGroupKeyResetLeader.c; path = ../asn.1/ElectGroupKeyResetLeader.c; sourceTree = "<group>"; };
438C43962167582400C7425B /* sync_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sync_api.h; path = ../src/sync_api.h; sourceTree = "<group>"; };
@ -744,6 +744,8 @@
64A8264B1B455C5600EECAF0 /* srcref */ = {
isa = PBXGroup;
children = (
436084222539A3B0005D56A7 /* sqlite3.c */,
436084232539A3B1005D56A7 /* sqlite3.h */,
43C3778D246A8C0300962D22 /* internal_format.c */,
43C37788246A8C0300962D22 /* internal_format.h */,
43188ABE23C4BBDD008EF79C /* distribution_codec.c */,
@ -771,8 +773,6 @@
43F73C052166282C00AB4524 /* key_reset.c */,
43F73C032166282C00AB4524 /* openpgp_compat.c */,
43F73C092166282C00AB4524 /* sync_api.c */,
4337082D203C075A004E6547 /* sqlite3.c */,
43370832203C075A004E6547 /* sqlite3.h */,
430BCC472015EE800077E998 /* pEp_string.c */,
430BCC462015EE800077E998 /* pEp_string.h */,
43F6921C1F164A47009418F5 /* resource_id.c */,
@ -894,7 +894,6 @@
15B037C822B2B822002D664C /* ISO639-1.h in Headers */,
15B037C922B2B822002D664C /* xer_decoder.h in Headers */,
43188A9923C4B2DE008EF79C /* Sync_func.h in Headers */,
43370834203C075A004E6547 /* sqlite3.h in Headers */,
15147EF1237E9EA7003989FE /* GroupHandshake.h in Headers */,
15B037D522B2B822002D664C /* TID.h in Headers */,
15B037AD22B2B822002D664C /* Rollback.h in Headers */,
@ -921,6 +920,7 @@
C46EBAEE216E445F0042A6A3 /* base64.h in Headers */,
15B037F722B2B822002D664C /* per_decoder.h in Headers */,
158FF95F23C49ED600CB1016 /* GroupKeysUpdate.h in Headers */,
436084252539A3B1005D56A7 /* sqlite3.h in Headers */,
15B037F022B2B822002D664C /* NegotiationOpen.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1163,7 +1163,6 @@
158FF96123C49ED600CB1016 /* Distribution.c in Sources */,
43F73C0B2166282C00AB4524 /* openpgp_compat.c in Sources */,
15B037F422B2B822002D664C /* ber_decoder.c in Sources */,
43370833203C075A004E6547 /* sqlite3.c in Sources */,
15B0380122B2B822002D664C /* asn_SET_OF.c in Sources */,
15B037DE22B2B822002D664C /* KeySync.c in Sources */,
15B75BE223FA9F9D00DAE976 /* SynchronizeGroupKeys.c in Sources */,
@ -1180,6 +1179,7 @@
430D258B1C9ED75A00B94535 /* blacklist.c in Sources */,
15B0380E22B2B822002D664C /* PrintableString.c in Sources */,
15B037E922B2B822002D664C /* CommitAcceptOfferer.c in Sources */,
436084242539A3B1005D56A7 /* sqlite3.c in Sources */,
43188AC023C4BBDE008EF79C /* distribution_codec.c in Sources */,
432713B023A10B07007EAD4A /* GroupKeysForNewMember.c in Sources */,
646C414E1D510D8800C63EFF /* baseprotocol.c in Sources */,

@ -1,78 +1,83 @@
@ECHO OFF
PUSHD .
SET pwd=%cd%
CD %pwd%\sync
:: The script is located in ...\pEpForWindowsAdapterSolution\pEpEngine\build-windows\
SET current_directory=%~dp0
:: Engine directory is ...\pEpForWindowsAdapterSolution\pEpEngine\
SET engine_directory=%current_directory:~0,-14%
:: YML2 directory is ...\pEpForWindowsAdapterSolution\yml2\
SET yml2_directory=%engine_directory:~0,-11%\yml2
:: Create the system.db
PUSHD %engine_directory%\db
CALL make_systemdb
IF NOT EXIST "%ProgramData%\pEp" "MKDIR %ProgramData%\pEp"
DEL "%ProgramData%\pEp\system.db"
MOVE system.db "%ProgramData%\pEp\system.db"
:: Generate code in ...\pEpEngine\sync
CD ..\sync
:: Make sure YML2 is installed
PY -m pip install wheel
PY -m pip install yml2
:: Generate the Sync code
IF NOT EXIST generated MKDIR generated
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_actions.ysl2 sync.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_actions.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_codec.ysl2 distribution.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_codec.ysl2 distribution.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_codec.ysl2 sync.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_codec.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_messages.ysl2 sync.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_messages.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_messages.ysl2 distribution.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_messages.ysl2 distribution.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_message_func.ysl2 sync.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_message_func.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
ECHO py "%YML_PATH%\yml2proc" -E utf-8 -y gen_statemachine.ysl2 sync.fsm
py "%YML_PATH%\yml2proc" -E utf-8 -y gen_statemachine.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
xcopy /y generated\*.asn1 ..\asn.1\
xcopy /y generated\*.c ..\src\
xcopy /y generated\*.h ..\src\
CD %pwd%\asn.1
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_actions.ysl2 sync.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_actions.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_codec.ysl2 distribution.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_codec.ysl2 distribution.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_codec.ysl2 sync.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_codec.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_messages.ysl2 sync.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_messages.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_messages.ysl2 distribution.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_messages.ysl2 distribution.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_message_func.ysl2 sync.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_message_func.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
ECHO PY -m yml2.yml2proc -E utf-8 -y gen_statemachine.ysl2 sync.fsm
PY -m yml2.yml2proc -E utf-8 -y gen_statemachine.ysl2 sync.fsm
IF %ERRORLEVEL% NEQ 0 GOTO end
XCOPY /y generated\*.asn1 ..\asn.1\
XCOPY /y generated\*.c ..\src\
XCOPY /y generated\*.h ..\src\
CD %engine_directory%\asn.1
DEL *.h
DEL *.c
..\..\Tools\asn1c\bin\asn1c -S ../../Tools/asn1c/share/asn1c -gen-PER -fincludes-quoted -fcompound-names -pdu=auto pEp.asn1 keysync.asn1 sync.asn1
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
IF %ERRORLEVEL% NEQ 0 GOTO end
..\..\Tools\asn1c\bin\asn1c -S ../../Tools/asn1c/share/asn1c -gen-PER -fincludes-quoted -fcompound-names -pdu=auto pEp.asn1 keyreset.asn1 distribution.asn1
IF %ERRORLEVEL% NEQ 0 (
POPD
EXIT /B 1
)
IF %ERRORLEVEL% NEQ 0 GOTO end
DEL *-sample.c
CD %pwd%\..
CD %engine_directory%\..
RD /S/Q pEp
MKDIR pEp
XCOPY pEpEngine\src\*.h pEp\ /Y/F/I
:end
POPD
EXIT /B %ERRORLEVEL%

@ -60,6 +60,9 @@
<Link>
<SubSystem>Windows</SubSystem>
</Link>
<PreBuildEvent>
<Command>IF EXIST ".\Debug\libpEpasn1.tlog\unsuccessfulbuild" CALL ..\generate_code.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -77,6 +80,9 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>IF EXIST ".\Release\libpEpasn1.tlog\unsuccessfulbuild" CALL ..\generate_code.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
@ -92,8 +98,4 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<Target Name="BeforeRebuild">
<Message Text="Generating Code for pEp Sync" />
<Exec Command="CD &quot;$(ProjectDir)..\..&quot; &amp;&amp; &quot;$(ProjectDir)..\generate_code.cmd&quot;" />
</Target>
</Project>

@ -87,8 +87,6 @@
</Link>
<PreBuildEvent>
<Command>cargo build --manifest-path="$(SolutionDir)sequoia\Cargo.toml" -p sequoia-openpgp-ffi</Command>
<Message>
</Message>
</PreBuildEvent>
<PostBuildEvent>
<Command>xcopy "$(SolutionDir)sequoia\target\debug\sequoia_openpgp_ffi.dll" "$(TargetDir)" /Y</Command>
@ -121,8 +119,6 @@
</Link>
<PreBuildEvent>
<Command>cargo build --manifest-path="$(SolutionDir)sequoia\Cargo.toml" --release -p sequoia-openpgp-ffi</Command>
<Message>
</Message>
</PreBuildEvent>
<PostBuildEvent>
<Command>xcopy "$(SolutionDir)sequoia\target\release\sequoia_openpgp_ffi.dll" "$(TargetDir)" /Y</Command>

File diff suppressed because it is too large Load Diff

@ -98,14 +98,15 @@ install_headers: $(TARGET)
mkdir -p $(PREFIX)/include/pEp
cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h \
timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h \
cryptotech.h sync_api.h blacklist.h pEp_string.h openpgp_compat.h mime.h \
cryptotech.h sync_api.h blacklist.h pEp_string.h openpgp_compat.h \
labeled_int_list.h key_reset.h base64.h sync_codec.h distribution_codec.h \
status_to_string.h aux_mime_msg.h keyreset_command.h platform.h platform_unix.h ../asn.1/*.h \
$(PREFIX)/include/pEp/
install: $(TARGET) install_headers
mkdir -p "$(PREFIX)/lib/"
cp $< $(PREFIX)/lib/
cp -v $< $(PREFIX)/lib/
cp -v libpEpEngine.a $(PREFIX)/lib/
beinstall: install
cp platform*.h $(PREFIX)/include/pEp/

@ -1,3 +1,6 @@
/** @file */
/** @brief File description for doxygen missing. FIXME */
// This file is under GNU General Public License 3.0
// see LICENSE.txt
@ -278,5 +281,6 @@ pEp_error:
return status;
}
#else
// This is here to please ISO C - it needs a compilation unit. Value will never be used.
const int the_answer_my_friend = 42;
#endif

@ -1,5 +1,16 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
/**
* @file aux_mime_msg.h
*
* @brief Auxiliary file which provides the MIME* functions for the enigmail/pEp implementation and some tests.
* Provides access to pEp functions for messages fed in in MIME string format instead of
* through the message struct.
*
* @deprecated These functions should no longer be used, and these files will be removed shortly.
*
* @warning No version of the engine which implements pEp sync should use these functions
*
* @license GNU General Public License 3.0 - see LICENSE.txt
*/
#pragma once
@ -14,29 +25,33 @@
extern "C" {
#endif
// MIME_encrypt_message() - encrypt a MIME message, with MIME output
//
// parameters:
// session (in) session handle
// mimetext (in) MIME encoded text to encrypt
// size (in) size of input mime text
// extra (in) extra keys for encryption
// mime_ciphertext (out) encrypted, encoded message
// enc_format (in) encrypted format
// flags (in) flags to set special encryption features
//
// return value:
// PEP_STATUS_OK if everything worked
// PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
// PEP_CANNOT_CREATE_TEMP_FILE
// if there are issues with temp files; in
// this case errno will contain the underlying
// error
// PEP_OUT_OF_MEMORY if not enough memory could be allocated
//
// caveat:
// the encrypted, encoded mime text will go to the ownership of the caller; mimetext
// will remain in the ownership of the caller
/**
* <!-- MIME_encrypt_message() -->
*
* @deprecated
*
* @brief Encrypt a MIME message, with MIME output
*
* @param[in] session session handle
* @param[in] mimetext MIME encoded text to encrypt
* @param[in] size size of input mime text
* @param[in] extra extra keys for encryption
* @param[out] mime_ciphertext encrypted, encoded message
* @param[in] enc_format encrypted format
* @param[in] flags flags to set special encryption features
*
* @retval PEP_STATUS_OK if everything worked
* @retval PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
* @retval PEP_CANNOT_CREATE_TEMP_FILE if there are issues with temp files; in
* this case errno will contain the underlying
* error
* @retval PEP_OUT_OF_MEMORY if not enough memory could be allocated
*
* @ownership
* - the encrypted, encoded mime text will go to the ownership of the caller
* - the original mimetext will remain in the ownership of the caller
*
*/
DYNAMIC_API PEP_STATUS MIME_encrypt_message(
PEP_SESSION session,
const char *mimetext,
@ -48,31 +63,36 @@ DYNAMIC_API PEP_STATUS MIME_encrypt_message(
);
// MIME_encrypt_message_for_self() - encrypt MIME message for user's identity only,
// ignoring recipients and other identities from
// the message, with MIME output
// parameters:
// session (in) session handle
// target_id (in) self identity this message should be encrypted for
// mimetext (in) MIME encoded text to encrypt
// size (in) size of input mime text
// extra (in) extra keys for encryption
// mime_ciphertext (out) encrypted, encoded message
// enc_format (in) encrypted format
// flags (in) flags to set special encryption features
//
// return value:
// PEP_STATUS_OK if everything worked
// PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
// PEP_CANNOT_CREATE_TEMP_FILE
// if there are issues with temp files; in
// this case errno will contain the underlying
// error
// PEP_OUT_OF_MEMORY if not enough memory could be allocated
//
// caveat:
// the encrypted, encoded mime text will go to the ownership of the caller; mimetext
// will remain in the ownership of the caller
/**
* <!-- MIME_encrypt_message_for_self() -->
*
* @deprecated
*
* @brief Encrypt MIME message for user's identity only,
* ignoring recipients and other identities from
* the message, with MIME output
*
* @param[in] session session handle
* @param[in] target_id self identity this message should be encrypted for
* @param[in] mimetext MIME encoded text to encrypt
* @param[in] size size of input mime text
* @param[in] extra extra keys for encryption
* @param[out] mime_ciphertext encrypted, encoded message
* @param[in] enc_format encrypted format
* @param[in] flags flags to set special encryption features
*
* @retval PEP_STATUS_OK if everything worked
* @retval PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
* @retval PEP_CANNOT_CREATE_TEMP_FILE if there are issues with temp files; in
* this case errno will contain the underlying
* error
* @retval PEP_OUT_OF_MEMORY if not enough memory could be allocated
*
* @ownership
* - the encrypted, encoded mime text will go to the ownership of the caller
* - the original mimetext will remain in the ownership of the caller
*
*/
DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
PEP_SESSION session,
pEp_identity* target_id,
@ -86,52 +106,66 @@ DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
// MIME_decrypt_message() - decrypt a MIME message, with MIME output
//
// parameters:
// session (in) session handle
// mimetext (in) MIME encoded text to decrypt
// size (in) size of mime text to decode (in order to decrypt)
// mime_plaintext (out) decrypted, encoded message
// keylist (inout) in: stringlist with additional keyids for reencryption if needed
// (will be freed and replaced with output keylist)
// out: stringlist with keyids
// rating (out) rating for the message
// flags (inout) flags to signal special decryption features (see below)
// modified_src (out) modified source string, if decrypt had reason to change it
//
// return value:
// decrypt status if everything worked with MIME encode/decode,
// the status of the decryption is returned
// (PEP_STATUS_OK or decryption error status)
// PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
// PEP_CANNOT_CREATE_TEMP_FILE
// if there are issues with temp files; in
// this case errno will contain the underlying
// error
// PEP_OUT_OF_MEMORY if not enough memory could be allocated
//
// flag values:
// in:
// PEP_decrypt_flag_untrusted_server
// used to signal that decrypt function should engage in behaviour
// specified for when the server storing the source is untrusted.
// out:
// PEP_decrypt_flag_own_private_key
// private key was imported for one of our addresses (NOT trusted
// or set to be used - handshake/trust is required for that)
// PEP_decrypt_flag_src_modified
// indicates that the modified_src field should contain a modified
// version of the source, at the moment always as a result of the
// input flags.
// PEP_decrypt_flag_consume
// used by sync
// PEP_decrypt_flag_ignore
// used by sync
//
// caveat:
// the decrypted, encoded mime text will go to the ownership of the caller; mimetext
// will remain in the ownership of the caller
/**
* <!-- MIME_decrypt_message() -->
*
* @deprecated
*
* @brief Decrypt a MIME message, with MIME output
*
* @param[in] session session handle
* @param[in] mimetext MIME encoded text to decrypt
* @param[in] size size of mime text to decode (in order to decrypt)
* @param[out] mime_plaintext decrypted, encoded message
* @param[in,out] keylist in: stringlist with additional keyids for reencryption if needed
* (will be freed and replaced with output keylist)
* out: stringlist with keyids
* @param[out] rating rating for the message
* @param[in,out] flags flags to signal special decryption features (see below)
* @param[out] modified_src modified source string, if decrypt had reason to change it
*
* @retval decrypt status if everything worked with MIME encode/decode,
* the status of the decryption is returned
* (PEP_STATUS_OK or decryption error status)
* @retval PEP_BUFFER_TOO_SMALL if encoded message size is too big to handle
* @retval PEP_CANNOT_CREATE_TEMP_FILE if there are issues with temp files; in
* this case errno will contain the underlying
* error
* @retval PEP_OUT_OF_MEMORY if not enough memory could be allocated
*
* @note Flags above are as follows:
* @verbatim
* ---------------------------------------------------------------------------------------------|
* Incoming flags |
* ---------------------------------------------------------------------------------------------|
* Flag | Description |
* --------------------------------------|------------------------------------------------------|
* PEP_decrypt_flag_untrusted_server | used to signal that decrypt function should engage |
* | in behaviour specified for when the server storing |
* | the source is untrusted. |
* ---------------------------------------------------------------------------------------------|
* Outgoing flags |
* ---------------------------------------------------------------------------------------------|
* PEP_decrypt_flag_own_private_key | private key was imported for one of our addresses |
* | (NOT trusted or set to be used - handshake/trust is |
* | required for that) |
* | |
* PEP_decrypt_flag_src_modified | indicates that the modified_src field should contain |
* | a modified version of the source, at the moment |
* | always as a result of the input flags. |
* | |
* PEP_decrypt_flag_consume | used by sync to indicate this was a pEp internal |
* | message and should be consumed externally without |
* | showing it as a normal message to the user |
* | |
* PEP_decrypt_flag_ignore | used by sync |
* ---------------------------------------------------------------------------------------------| @endverbatim
*
* @ownership
* - the decrypted, encoded mime text will go to the ownership of the caller
* - the original mimetext will remain in the ownership of the caller
*
*/
DYNAMIC_API PEP_STATUS MIME_decrypt_message(
PEP_SESSION session,
const char *mimetext,

@ -1,3 +1,6 @@
/** @file */
/** @brief File description for doxygen missing. FIXME */
// This file is under GNU General Public License 3.0
// see LICENSE.txt
@ -25,6 +28,16 @@ static char translate_char_to_bits(char input) {
return -1;
}
/**
* @internal
*
* <!-- _is_whitespace() -->
*
* @brief TODO
*
* @param[in] in constchar
*
*/
static bool _is_whitespace(const char in) {
switch (in) {
case ' ':
@ -37,6 +50,17 @@ static bool _is_whitespace(const char in) {
}
}
/**
* @internal
*
* <!-- subtract_whitespace() -->
*
* @brief TODO
*
* @param[in] *input constchar
* @param[in] length int
*
*/
static size_t subtract_whitespace(const char* input, int length) {
size_t actual_size = length;
int i;
@ -48,6 +72,17 @@ static size_t subtract_whitespace(const char* input, int length) {
return actual_size;
}
/**
* @internal
*
* <!-- trim_end() -->
*
* @brief TODO
*
* @param[in] *input constchar
* @param[in] *length int
*
*/
static void trim_end(const char* input, int* length) {
const char* end = input + *length;
@ -62,6 +97,17 @@ static void trim_end(const char* input, int* length) {
}
}
/**
* @internal
*
* <!-- next_char() -->
*
* @brief TODO
*
* @param[in] **input_ptr constchar
* @param[in] *end constchar
*
*/
char next_char(const char** input_ptr, const char* end) {
const char* input = *input_ptr;
char this_ch = 0;
@ -80,6 +126,17 @@ char next_char(const char** input_ptr, const char* end) {
}
// 4 chars = 3 output bytes
/**
* @internal
*
* <!-- base64_str_to_binary_blob() -->
*
* @brief TODO
*
* @param[in] *input const char
* @param[in] length int
*
*/
bloblist_t* base64_str_to_binary_blob(const char* input, int length) {
if (length == 0)
return NULL;

@ -1,5 +1,10 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
/**
* @file base64.h
* @brief Convert base64 to a binary blob - this is a convenience function
* used mainly to convert keys which are base64 rather than radix64
* (i.e. PGP armoured) encoded
* @license GNU General Public License 3.0 - see LICENSE.txt
*/
#pragma once
@ -10,6 +15,17 @@
extern "C" {
#endif
/**
* <!-- base64_str_to_binary_blob() -->
*
* @brief Decode a base64 string and return binary format
*
* @param[in] input base64 string
* @param[in] length string length
*
* @retval decoded binary blob of input string
*
*/
bloblist_t* base64_str_to_binary_blob(const char* input, int length);
#ifdef __cplusplus

@ -1,3 +1,6 @@
/** @file */
/** @brief File description for doxygen missing. FIXME */
// This file is under GNU General Public License 3.0
// see LICENSE.txt
@ -5,11 +8,23 @@
#include "message_api.h"
#include "baseprotocol.h"
static const char *_base_type[] = {
"application/pEp.sign",
"application/pEp.sync",
"application/pEp.distribution"
};
static PEP_STATUS _get_base_protocol_type_str(base_protocol_type type, const char** type_str) {
*type_str = NULL;
switch(type) {
case BASE_SIGN:
*type_str = _BASE_PROTO_MIME_TYPE_SIGN;
break;
case BASE_SYNC:
*type_str = _BASE_PROTO_MIME_TYPE_SYNC;
break;
case BASE_KEYRESET:
*type_str = _BASE_PROTO_MIME_TYPE_DIST;
break;
default:
return PEP_ILLEGAL_VALUE;
}
return PEP_STATUS_OK;
}
PEP_STATUS base_decorate_message(
PEP_SESSION session,
@ -32,18 +47,27 @@ PEP_STATUS base_decorate_message(
bloblist_t *bl;
const char* type_str = NULL;
switch (type) {
case BASE_SYNC:
bl = bloblist_add(msg->attachments, payload, size,
_base_type[type], "sync.pEp");
_BASE_PROTO_MIME_TYPE_SYNC, "sync.pEp");
break;
case BASE_KEYRESET:
bl = bloblist_add(msg->attachments, payload, size,
_base_type[type], "distribution.pEp");
_BASE_PROTO_MIME_TYPE_DIST, "distribution.pEp");
break;
default:
status = _get_base_protocol_type_str(type, &type_str);
if (status != PEP_STATUS_OK)
return status;
else if (!type_str)
return PEP_UNKNOWN_ERROR;
bl = bloblist_add(msg->attachments, payload, size,
_base_type[type], "ignore_this_attachment.pEp");
type_str, "ignore_this_attachment.pEp");
type_str = NULL;
}
if (bl == NULL)
@ -61,7 +85,7 @@ PEP_STATUS base_decorate_message(
assert(sign && sign_size);
bl = bloblist_add(bl, sign, sign_size,
_base_type[BASE_SIGN], "electronic_signature.asc");
_BASE_PROTO_MIME_TYPE_SIGN, "electronic_signature.asc");
if (!bl)
goto enomem;
}
@ -162,8 +186,14 @@ PEP_STATUS base_extract_message(
size_t _sign_size = 0;
stringlist_t *keylist = NULL;
const char* type_str = NULL;
status = _get_base_protocol_type_str(type, &type_str);
if (status != PEP_STATUS_OK || !type_str)
return status;
for (bloblist_t *bl = msg->attachments; bl ; bl = bl->next) {
if (bl->mime_type && strcasecmp(bl->mime_type, _base_type[type]) == 0) {
if (bl->mime_type && strcasecmp(bl->mime_type, type_str) == 0) {
if (!_payload) {
_payload = bl->value;
_payload_size = bl->size;
@ -173,7 +203,7 @@ PEP_STATUS base_extract_message(
goto the_end;
}
}
else if (bl->mime_type && strcasecmp(bl->mime_type, _base_type[BASE_SIGN]) == 0) {
else if (bl->mime_type && strcasecmp(bl->mime_type, _BASE_PROTO_MIME_TYPE_SIGN) == 0) {
if (!_sign) {
_sign = bl->value;
_sign_size = bl->size;

@ -1,5 +1,11 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
/**
* @file baseprotocol.h
* @brief Basic functions for administrative pEp messages (preparation,
* decoration, payload, extraction, etc.). These are used for
* protocol messages in, for example, key sync and key reset.
* The payloads of these messages are, in general, not human-readable.
* @license GNU General Public License 3.0 - see LICENSE.txt
*/
#pragma once
@ -9,31 +15,43 @@
extern "C" {
#endif
#define _BASE_PROTO_MIME_TYPE_SIGN "application/pEp.sign"
#define _BASE_PROTO_MIME_TYPE_SYNC "application/pEp.sync"
#define _BASE_PROTO_MIME_TYPE_DIST "application/pEp.distribution"
/**
* @enum base_protocol_type
*
* @brief TODO
*
*/
typedef enum _base_protocol_type {
BASE_SIGN = 0,
BASE_SYNC = 1,
BASE_KEYRESET = 2
} base_protocol_type;
// base_decorate_message() - decorate a message with payload
//
// parameters:
// session (in) session handle
// msg (inout) message to decorate
// type (in) base protocol type
// payload (in) payload to send
// size (in) size of payload
// fpr (in) optional key to sign or NULL
//
// returns:
// PEP_STATUS_OK and result on success or an error on failure
//
// caveat:
// on success (and only then) payload goes to the ownership of the msg
// the ownership of the msg remains with the caller
/**
* <!-- base_decorate_message() -->
*
* @brief Decorate a message with payload
*
* @param[in] session session handle
* @param[in,out] msg message to decorate (contains return result on success)
* @param[in] type base protocol type
* @param[in] payload payload to send
* @param[in] size size of payload
* @param[in] fpr optional key to sign or NULL
*
* @retval PEP_STATUS_OK on success
* @retval error_status on failure
*
* @ownership
* - On success (and only then), ownership of the payload is assigned to the msg structure
* - Ownership of the msg remains with the caller
*
*/
PEP_STATUS base_decorate_message(
PEP_SESSION session,
@ -45,24 +63,28 @@ PEP_STATUS base_decorate_message(
);
// base_prepare_message() - prepare a sync message with payload
//
// parameters:
// session (in) session handle
// me (in) identity to use for the sender
// partner (in) identity to use for the receiver
// type (in) base protocol type
// payload (in) payload to send
// size (in) size of payload
// fpr (in) optional key to sign or NULL
// result (out) message with payload
//
// returns:
// PEP_STATUS_OK and result on success or an error on failure
//
// caveat:
// on success (and only then) payload goes to the ownership of the result
// the ownership of the result goes to the caller
/**
* <!-- base_prepare_message() -->
*
* @brief Prepare a sync message with payload
*
* @param[in] session session handle
* @param[in] me identity to use for the sender
* @param[in] partner identity to use for the receiver
* @param[in] type base protocol type
* @param[in] payload payload to send
* @param[in] size size of payload
* @param[in] fpr optional key to sign or NULL
* @param[out] result returned message with payload on success
*
* @retval PEP_STATUS_OK on success
* @retval error_status on failure
*
* @ownership
* - On (and only on) success, ownership of payload is assigned to the result structure
* - Ownership of the result goes to the caller
*
*/
PEP_STATUS base_prepare_message(
PEP_SESSION session,
@ -76,25 +98,30 @@ PEP_STATUS base_prepare_message(
);
// base_extract_message() - extract a sync message from a pEp message
//
// parameters:
// session (in) session handle
// msg (in) message to analyze
// type (in) base protocol type to extract
// size (out) size of extracted payload or 0 if not found
// payload (out) extraced payload
// fpr (out) if message was correctly signed then fpr of signature's
// key, otherwise NULL
//
// returns:
// PEP_STATUS_OK and payload == NULL if no sync message
// PEP_STATUS_OK and payload, size if sync message found
// any other value on error
//
// caveat:
// payload may point to msg attachment, the ownership does not change
// the ownership of fpr goes to the caller
/**
* <!-- base_extract_message() -->
*
* @brief Extract a sync message from a pEp message
*
* @param[in] session session handle
* @param[in] msg message to analyze
* @param[in] type base protocol type to extract
* @param[out] size size of extracted payload, or 0 if not found
* @param[out] payload extracted payload, if sync message is found.
* otherwise, NULL
* @param[out] fpr if message was correctly signed then fpr of signature's
* key, otherwise NULL
*
* @retval PEP_STATUS_OK if no error occurred, whether or not sync message was found
* @retval error_status any other value on error
*
* @ownership
* - Payload may point to msg attachment, but the ownership does not change
* - If fpr != NULL the ownership goes to the caller
*
* @todo Volker, expand this definition from sync message. What do we call these? Administrative messages? - K
*
*/
PEP_STATUS base_extract_message(
PEP_SESSION session,
@ -106,10 +133,31 @@ PEP_STATUS base_extract_message(
);
// this is the internal function to be used by asynchronous network protocol
// implementations
//
// this function is calling messageToSend(NULL) in case there is a missing or wrong passphrase
/**
* <!-- try_base_prepare_message() -->
*
* @brief Prepare a sync message with payload. This is the internal function to be used by
* asynchronous network protocol implementations. This function differs from
* base_prepare_message in that it calls messageToSend(NULL) in case there is a missing
* or wrong passphrase, but more explanation is required here.
*
* @param[in] session session handle
* @param[in] me identity to use for the sender
* @param[in] partner identity to use for the receiver
* @param[in] type base protocol type
* @param[in] payload payload to send
* @param[in] size size of payload
* @param[in] fpr optional key to sign or NULL
* @param[out] result returned message with payload on success
*
* @ownership
* - On (and only on) success, ownership of payload is assigned to the result structure
* - Ownership of the result goes to the caller
*
* @todo Volker, I need a better explanation of the use case here to document correctly - K
*
* @see base_prepare_message()
*/
PEP_STATUS try_base_prepare_message(
PEP_SESSION session,

@ -1,3 +1,6 @@
/** @file */
/** @brief File description for doxygen missing. FIXME */
// This file is under GNU General Public License 3.0
// see LICENSE.txt

@ -1,5 +1,17 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
/**
* @file blacklist.h
* @brief Functions for maintaining a key blacklist for OpenPGP keys
* (i.e. keys received from OpenPGP partners). This is currently
* used by users when an OpenPGP partner has indicated that they
* do not want us to use a particular key we may have for them.
* This is marked as deprecated because we want users to use
* key reset instead, and this code will be in fact removed
* in Release 2.2.0 when key election is also removed.
*
* @deprecated These files are still in use as of Release 2.1 and will be removed with key election removal.
*
* @license GNU General Public License 3.0 - see LICENSE.txt
*/
#pragma once
@ -9,37 +21,56 @@
extern "C" {
#endif
// blacklist_add() - add to blacklist
//
// parameters:
// session (in) session to use
// fpr (in) fingerprint of key to blacklist
//
// caveat:
// there is no point in blacklisting an own key; for any own
// identity, this will be ignored. The correct function to use
// for own keys in this event is "key_reset_trust".
// Also, this is only effective for OpenPGP-level trust. If
// this key is for a pEp user, the blacklist is ignored.
/**
* <!-- blacklist_add() -->
*
* @deprecated As of Release 2.2.0
*
* @brief Add to blacklist
*
* @param[in] session session to use
* @param[in] fpr fingerprint of key to blacklist
*
* @warning there is no point in blacklisting an own key; for any own
* identity, this will be ignored. The correct function to use
* for own keys in this event is "key_reset_trust".
* Also, this is only effective for OpenPGP-level trust. If
* this key is for a pEp user, the blacklist is ignored.
*
*/
DYNAMIC_API PEP_STATUS blacklist_add(PEP_SESSION session, const char *fpr);
// blacklist_delete() - delete from blacklist
//
// parameters:
// session (in) session to use
// fpr (in) fingerprint of key to be removed from blacklist
/**
* <!-- blacklist_delete() -->
*
* @deprecated As of Release 2.2.0
*
* @brief Delete from blacklist
*
* @param[in] session session to use
* @param[in] fpr fingerprint of key to be removed from blacklist
*
*
*/
DYNAMIC_API PEP_STATUS blacklist_delete(PEP_SESSION session, const char *fpr);
// blacklist_is_listed() - is_listed in blacklist
//
// parameters:
// session (in) session to use
// fpr (in) fingerprint of key to blacklist
// bool (out) flags if key is blacklisted
/**
* <!-- blacklist_is_listed() -->
*
* @deprecated As of Release 2.2.0
*
* @brief Is listed in blacklist
*
* @param[in] session session to use
* @param[in] fpr fingerprint of key to blacklist
* @param[out] bool flags if key is blacklisted
*
*
*/
DYNAMIC_API PEP_STATUS blacklist_is_listed(
PEP_SESSION session,
@ -48,14 +79,19 @@ DYNAMIC_API PEP_STATUS blacklist_is_listed(
);
// blacklist_retrieve() - retrieve full blacklist of key fingerprints
//
// parameters:
// session (in) session to use
// blacklist (out) copy of blacklist
//
// caveat:
// the ownership of the copy of blacklist goes to the caller
/**
* <!-- blacklist_retrieve() -->
*
* @deprecated As of Release 2.2.0
*
* @brief Retrieve full blacklist of key fingerprints
*
* @param[in] session session to use
* @param[out] blacklist copy of blacklist
*
* @ownership the ownership of the copy of blacklist goes to the caller
*
*/
DYNAMIC_API PEP_STATUS blacklist_retrieve(
PEP_SESSION session,

@ -1,3 +1,6 @@
/** @file */
/** @brief File description for doxygen missing. FIXME */
// This file is under GNU General Public License 3.0
// see LICENSE.txt
@ -80,47 +83,37 @@ DYNAMIC_API bloblist_t *bloblist_dup(const bloblist_t *src)
assert(src);
if (src == NULL)
return NULL;
bloblist_t *bloblist = NULL;
// head
char *blob2 = malloc(src->size);
assert(blob2);
if (blob2 == NULL)
goto enomem;
bloblist_t* head_ptr = NULL;
bloblist_t** dst_curr_ptr = &head_ptr;
memcpy(blob2, src->value, src->size);
bloblist = new_bloblist(blob2, src->size, src->mime_type, src->filename);
if (bloblist == NULL)
goto enomem;
blob2 = NULL;
const bloblist_t* src_curr = src;
bloblist_t* src_curr = src->next;
bloblist_t** dst_curr_ptr = &bloblist->next;
char* blob2 = NULL;
// list
while (src_curr) {
for ( ; src_curr; src_curr = src_curr->next, dst_curr_ptr = &((*dst_curr_ptr)->next)) {
blob2 = malloc(src_curr->size);
assert(blob2);
if (blob2 == NULL)
goto enomem;
// This is why we don't calloc
memcpy(blob2, src_curr->value, src_curr->size);
*dst_curr_ptr = new_bloblist(blob2, src_curr->size, src_curr->mime_type, src_curr->filename);
if (*dst_curr_ptr == NULL)
goto enomem;
src_curr = src_curr->next;
dst_curr_ptr = &((*dst_curr_ptr)->next);
}
return bloblist;
if (!head_ptr)
return NULL;
return head_ptr;
enomem:
free(blob2);
free_bloblist(bloblist);
free_bloblist(head_ptr);
return NULL;
}
@ -154,7 +147,7 @@ DYNAMIC_API bloblist_t *bloblist_add(bloblist_t *bloblist, char *blob, size_t si
list_curr = list_curr->next;
list_curr->next = new_bloblist(blob, size, mime_type, filename);
list_curr->release_value = release_value;
list_curr->next->release_value = release_value;
assert(list_curr->next);
if (!list_curr->next)
@ -168,7 +161,10 @@ DYNAMIC_API bloblist_t* bloblist_join(bloblist_t* first, bloblist_t* second) {
return second;
if (!second)
return first;
if (first == second)
return first;
bloblist_t* list_curr = first;
while (list_curr->next) {

@ -1,5 +1,9 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
/**
* @file bloblist.h
* @brief functions for list structure to hold data of unspecified format (hence,
* "blob list"); can contain addition format information in structure's mime info
* @license GNU General Public License 3.0 - see LICENSE.txt
*/
#pragma once
@ -12,12 +16,24 @@
extern "C" {
#endif
/**
* @enum content_disposition_type
*
* @brief TODO
*
*/
typedef enum {
PEP_CONTENT_DISP_ATTACHMENT = 0,
PEP_CONTENT_DISP_INLINE = 1,
PEP_CONTENT_DISP_OTHER = -1 // must be affirmatively set
} content_disposition_type;
/**
* @struct bloblist_t
*
* @brief TODO
*
*/
typedef struct _bloblist_t {
char *value; // blob
size_t size; // size of blob
@ -34,98 +50,139 @@ typedef struct _bloblist_t {
} bloblist_t;
// new_bloblist() - allocate a new bloblist
//
// parameters:
// blob (in) blob to add to the list
// size (in) size of the blob
// mime_type (in) MIME type of the blob data or NULL if unknown
// filename (in) file name of origin of blob data or NULL if unknown
//
// return value:
// pointer to new bloblist_t or NULL if out of memory
//
// caveat:
// the ownership of the blob goes to the bloblist; mime_type and filename
// are being copied, the originals remain in the ownership of the caller
//
// if blob is on a different heap then after the call release_value has to
// be set by the adapter; this is relevant on operating systems with
// multiple heaps like Microsoft Windows
/**
* <!-- new_bloblist() -->
*
* @brief Allocate a new bloblist
*
* @param[in] blob blob to add to the list
* @param[in] size size of the blob
* @param[in] mime_type MIME type of the blob data or NULL if unknown
* @param[in] filename file name of origin of blob data or NULL if unknown
*
* @retval pointer to new bloblist_t or NULL if out of memory
*
* @ownership
* - the ownership of the blob goes to the bloblist struct
* - mime_type and filename are copied (copies belong to bloblist struct,
* the originals remain in the ownership of the caller)
*
* @warning if blob is on a different heap, then after the call, release_value has to
* be set by the adapter; this is relevant on operating systems with
* multiple heaps like Microsoft Windows
*
*/
DYNAMIC_API bloblist_t *new_bloblist(char *blob, size_t size, const char *mime_type,
const char *filename);
// free_bloblist() - free bloblist
//
// parameters:
// bloblist (in) bloblist to free
/**
* <!-- free_bloblist() -->
*
* @brief Free bloblist
*
* @param[in] bloblist bloblist to free
*
*
*/
DYNAMIC_API void free_bloblist(bloblist_t *bloblist);
// bloblist_dup() - duplicate bloblist
//
// parameters:
// src (in) bloblist to duplicate
//
// return value:
// pointer to a new bloblist_t or NULL if out of memory
//
// caveat:
// this is an expensive operation because all blobs are copied
/**
* <!-- bloblist_dup() -->
*
* @brief Duplicate bloblist
*
* @param[in] src bloblist to duplicate
*
* @retval pointer to a new bloblist_t or NULL if out of memory
*
* @warning this is an expensive operation because all blobs are copied
*
*/
DYNAMIC_API bloblist_t *bloblist_dup(const bloblist_t *src);
// bloblist_add() - add reference to a blob to bloblist
//
// parameters:
// bloblist (in) bloblist to add to
// blob (in) blob
// size (in) size of the blob
// mime_type (in) MIME type of the blob or NULL if unknown
// filename (in) file name of the blob or NULL if unknown
//
// return value:
// pointer to the last element of bloblist or NULL if out of memory or
// NULL passed in as blob value
//
// caveat:
// the ownership of the blob goes to the bloblist; mime_type and filename
// are being copied, the originals remain in the ownership of the caller.
// bloblist input parameter equal to NULL or with value == NULL is a valid
// empty input list.
//
// If there is release_value set in bloblist it is copied to the added
// leaf
/**
* <!-- bloblist_add() -->
*
* @brief Add reference to a blob to bloblist
*
* @param[in] bloblist bloblist to a