pull/62/head Release_0.0.1
David Lanzendörfer 1 year ago
commit acbbf1db83

@ -4,14 +4,33 @@ include:
stages:
- deps
- build
- build-docker
- packages
# Debian
debian10:build:
debian10:deps:
extends: .make_in_docker
stage: deps
variables:
MAKE_TARGET: "deps"
CI_DISTRO_TARGET: "debian10"
DEBIAN_FRONTEND: "noninteractive"
rules:
- changes:
- DEPENDENCIES
- scripts/debian10/deps.pEpEngine.debian10.Dockerfile
- scripts/common/build_pEpEngine_deps.sh
debian10:build:
tags:
- linux
stage: build
image: ${DOCKER_REGISTRY_HOST}/pep-debian10-engine-deps:latest
script:
- cd scripts/${CI_DISTRO_TARGET}
- make ${MAKE_TARGET}
variables:
MAKE_TARGET: "build"
CI_DISTRO_TARGET: "debian10"
@ -20,8 +39,13 @@ debian10:build:
- if: '$CI_COMMIT_TAG !~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
debian10:tagged-build:
extends: .make_in_docker
tags:
- linux
stage: build
image: ${DOCKER_REGISTRY_HOST}/pep-debian10-engine-deps:latest
script:
- cd scripts/${CI_DISTRO_TARGET}
- make ${MAKE_TARGET}
variables:
MAKE_TARGET: "build"
CI_DISTRO_TARGET: "debian10"
@ -30,6 +54,29 @@ debian10:tagged-build:
rules:
- if: '$CI_COMMIT_TAG =~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
debian10:build-docker:
extends: .make_in_docker
stage: build-docker
needs: ["debian10:build"]
variables:
MAKE_TARGET: "build-docker"
CI_DISTRO_TARGET: "debian10"
DEBIAN_FRONTEND: "noninteractive"
rules:
- if: '$CI_COMMIT_TAG !~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
debian10:tagged-build-docker:
extends: .make_in_docker
stage: build-docker
needs: ["debian10:tagged-build"]
variables:
MAKE_TARGET: "build-docker"
CI_DISTRO_TARGET: "debian10"
DEBIAN_FRONTEND: "noninteractive"
TAGGED_BUILD: "true"
rules:
- if: '$CI_COMMIT_TAG =~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
# CentOS
centos8:deps:
@ -41,11 +88,18 @@ centos8:deps:
rules:
- changes:
- DEPENDENCIES
- scripts/centos8/deps.pEpEngine.centos8.Dockerfile
- scripts/common/build_pEpEngine_deps.sh
centos8:build:
extends: .make_in_docker
tags:
- linux
stage: build
image: ${DOCKER_REGISTRY_HOST}/pep-centos8-engine-deps:latest
script:
- cd scripts/${CI_DISTRO_TARGET}
- make ${MAKE_TARGET}
variables:
MAKE_TARGET: "build"
CI_DISTRO_TARGET: "centos8"
@ -53,8 +107,13 @@ centos8:build:
- if: '$CI_COMMIT_TAG !~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
centos8:tagged-build:
extends: .make_in_docker
tags:
- linux
stage: build
image: ${DOCKER_REGISTRY_HOST}/pep-centos8-engine-deps:latest
script:
- cd scripts/${CI_DISTRO_TARGET}
- make ${MAKE_TARGET}
variables:
MAKE_TARGET: "build"
CI_DISTRO_TARGET: "centos8"
@ -62,10 +121,31 @@ centos8:tagged-build:
rules:
- if: '$CI_COMMIT_TAG =~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
centos8:build-docker:
extends: .make_in_docker
stage: build-docker
needs: ["centos8:build"]
variables:
MAKE_TARGET: "build-docker"
CI_DISTRO_TARGET: "centos8"
rules:
- if: '$CI_COMMIT_TAG !~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
centos8:tagged-build-docker:
extends: .make_in_docker
stage: build-docker
needs: ["centos8:tagged-build"]
variables:
MAKE_TARGET: "build-docker"
CI_DISTRO_TARGET: "centos8"
TAGGED_BUILD: "true"
rules:
- if: '$CI_COMMIT_TAG =~ /^Release_[0-9]+\.[0-9]+\.[0-9]+$/'
centos8:rpm:
extends: .make_in_docker
stage: packages
needs: ["centos8:build"]
needs: ["centos8:build-docker"]
variables:
MAKE_TARGET: "rpm"
CI_DISTRO_TARGET: "centos8"
@ -76,7 +156,7 @@ centos8:rpm:
centos8:rpm:tagged-build:
extends: .upload_pkg
stage: packages
needs: ["centos8:tagged-build"]
needs: ["centos8:tagged-build-docker"]
variables:
MAKE_TARGET: "rpm"
CI_DISTRO_TARGET: "centos8"

@ -19,7 +19,7 @@ STORAGE_FILES = $(addsuffix .asn1, $(STORAGE))
.PHONY: all clean install uninstall
all: Sync.c Distribution.c Storage.c
all: Sync.c Distribution.c Storage.c ASN1Message.c
$(MAKE) libasn1.a
libasn1.a: $(ALL_OBJECTS)
@ -43,6 +43,11 @@ Storage.c: $(STORAGE_FILES) pEp.asn1
rm -f converter-sample.c
touch Storage.c
ASN1Message.c: message.asn1 pEp.asn1
$(ASN1C) -gen-PER $(ASN1C_OPTIONS) $+
rm -f converter-sample.c
touch ASN1Message.c
clean:
rm -f *.a *.o *.c *.h *.sample \
$(SYNC_FILES) $(DISTRIBUTION_FILES) $(STORAGE_FILES)

@ -0,0 +1,94 @@
-- This file is under BSD License 2.0
--
-- Sync protocol for p≡p
-- Copyright (c) 2021 p≡p foundation
--
-- Written by Hartmut Goebel
PEP-MESSAGE {
iso(1) org(3) dod(6) internet(1) private(4)
enterprise(1) pEp(47878) message(1)
}
DEFINITIONS
AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::=
BEGIN
EXPORTS ASN1Message;
IMPORTS
PString, PStringList, Identity, IdentityList, PStringPairList, Hash
FROM PEP { iso(1) org(3) dod(6) internet(1) private(4)
enterprise(1) pEp(47878) basic(0) };
MessageDirection ::= ENUMERATED {
incoming (0),
outgoing (1)
}
ContentDisposition ::= ENUMERATED {
attachment (0),
inline (1),
other (2)
}
PBlob ::= SEQUENCE {
value OCTET STRING (SIZE(0..102400000)), -- up to 100 MB
mime-type PString OPTIONAL,
filename PString OPTIONAL,
disposition ContentDisposition
}
PBlobList ::= SEQUENCE OF PBlob
-- For the purposes of this profile, GeneralizedTime values MUST be
-- expressed in Coordinated Universal Time (UTC) and MUST include seconds
-- (i.e., times are YYYYMMDDHHMMSSZ), even where the number of seconds
-- is zero. GeneralizedTime values MUST NOT include fractional seconds.
ASN1Message ::= SEQUENCE {
direction MessageDirection OPTIONAL, -- used only in "inner" messages
id PString OPTIONAL, -- UTF-8 string of message ID
sent GeneralizedTime OPTIONAL, -- when the message is sent
recv GeneralizedTime OPTIONAL, -- when the message is received
from Identity, -- whom the message is from
-- At least one of to, cc must not be an empty list
-- FIXME: Can this be constrained?
to IdentityList OPTIONAL, -- whom the message is to
cc IdentityList OPTIONAL, -- whom a CC is being sent
bcc IdentityList OPTIONAL, -- whom a BCC is being sent
recv-by Identity OPTIONAL, -- via which identity the message
-- is received
reply-to IdentityList OPTIONAL, -- where a reply should go to
in-reply-to PStringList OPTIONAL, -- list of UTF-8 strings with
-- MessageIDs of refering messages
-- internal: refering_msg_ref
references PStringList OPTIONAL, -- list of UTF-8 strings with
-- references
-- internal: refered_by _message-ref-list
keywords PStringList OPTIONAL, -- list of UTF-8 strings with keywords
comments PString OPTIONAL, -- UTF-8 string with comments
opt-fields PStringPairList OPTIONAL, -- optional fields
sender-fpr Hash OPTIONAL, -- fingerprint of sending signer
-- At least one of shortmsg, longmsg, longmsg-formatted must be present
-- FIXME: Can this be constrained?
shortmsg PString OPTIONAL, -- UTF-8 string of short message
-- longmsg must only be used if implementation can handle dynamic allocation
longmsg UTF8String OPTIONAL, -- UTF-8 string of long message
-- (plain)
-- longmsg-formatted must only be used if implementation can handle
-- dynamic allocation
longmsg-formatted UTF8String OPTIONAL, -- UTF-8 string of long message
-- (formatted)
attachments PBlobList OPTIONAL -- blobs with attachments
-- internal: rawmsg
}
END

@ -12,12 +12,13 @@ DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::=
BEGIN
EXPORTS Identity, IdentityList, TID, Hash, Version, Rating;
EXPORTS Identity, IdentityList, TID, Hash, Version, Rating, PString, PStringList, PStringPair, PStringPairList;
ISO639-1 ::= PrintableString(FROM ("a".."z")) (SIZE(2))
Hex ::= PrintableString(FROM ("A".."F") | FROM ("0".."9"))
Hex ::= PrintableString(FROM ("A".."F" | "0".."9"))
Hash ::= Hex(SIZE(16..128)) -- 32bit Key ID to SHA512 in hex
PString ::= UTF8String (SIZE(1..1024))
PString ::= UTF8String (SIZE(0..1024))
PStringList ::= SEQUENCE OF PString
TID ::= OCTET STRING (SIZE(16)) -- UUID version 4 variant 1
Identity ::= SEQUENCE {
@ -62,5 +63,12 @@ Rating ::= ENUMERATED {
under-attack (-3)
}
PStringPair ::= SEQUENCE {
key PString,
value PString
}
PStringPairList ::= SEQUENCE OF PStringPair
END

@ -34,7 +34,6 @@
1543DA4C2577F8BE0041EFB5 /* Sync_event.h in Headers */ = {isa = PBXBuildFile; fileRef = 43188A8823C4B2DD008EF79C /* Sync_event.h */; };
1543DAA9257801880041EFB5 /* baseprotocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 646C414C1D510D8800C63EFF /* baseprotocol.c */; };
1543DAAD257801A90041EFB5 /* resource_id.c in Sources */ = {isa = PBXBuildFile; fileRef = 43F6921C1F164A47009418F5 /* resource_id.c */; };
1549181222B92EA20091B6D6 /* libiconv.2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1549180D22B92EA20091B6D6 /* libiconv.2.tbd */; };
154918AB22B940200091B6D6 /* fsm_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 1549189222B9401D0091B6D6 /* fsm_common.h */; platformFilter = ios; };
154918AC22B940200091B6D6 /* status_to_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 1549189322B9401E0091B6D6 /* status_to_string.h */; platformFilter = ios; };
154918B222B940200091B6D6 /* aux_mime_msg.h in Headers */ = {isa = PBXBuildFile; fileRef = 1549189922B9401E0091B6D6 /* aux_mime_msg.h */; platformFilter = ios; };
@ -310,7 +309,6 @@
154917FA22B926700091B6D6 /* libsequoia_openpgp_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsequoia_openpgp_ffi.a; path = ../../sequoia4ios/build/lib/libsequoia_openpgp_ffi.a; sourceTree = "<group>"; };
154917FB22B926700091B6D6 /* libhogweed.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libhogweed.a; path = ../../sequoia4ios/build/lib/libhogweed.a; sourceTree = "<group>"; };
154917FC22B926700091B6D6 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgmp.a; path = ../../sequoia4ios/build/lib/libgmp.a; sourceTree = "<group>"; };
1549180D22B92EA20091B6D6 /* libiconv.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.2.tbd; path = usr/lib/libiconv.2.tbd; sourceTree = SDKROOT; };
1549189222B9401D0091B6D6 /* fsm_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fsm_common.h; path = ../src/fsm_common.h; sourceTree = "<group>"; };
1549189322B9401E0091B6D6 /* status_to_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = status_to_string.h; path = ../src/status_to_string.h; sourceTree = "<group>"; };
1549189922B9401E0091B6D6 /* aux_mime_msg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = aux_mime_msg.h; path = ../src/aux_mime_msg.h; sourceTree = "<group>"; };
@ -426,7 +424,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1549181222B92EA20091B6D6 /* libiconv.2.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -546,7 +543,6 @@
1585EF5A26A08B2000B822E1 /* CommonPEPDependencies.xcodeproj */,
15A3261C2611F6B5009D07EB /* PEPSQLITE3.xcodeproj */,
15A3203B260E030B009D07EB /* pEpASN1.xcodeproj */,
1549180D22B92EA20091B6D6 /* libiconv.2.tbd */,
64951A1B1BE0FCD800B10E71 /* system.db */,
64DA24121B832EBA000BEE80 /* libetpan.xcodeproj */,
43188A5523C4A7F8008EF79C /* sync-generated */,

@ -44,5 +44,5 @@ svg: $(patsubst %.dot,%.svg,$(wildcard *.dot))
$(YML2_PROC) -y gen_dot.ysl2 $< -o $@
%.svg: %.dot
dot -Tsvg -o $@ $<
dot -Tsvg $< -o $@ > /dev/null

@ -152,8 +152,13 @@ tstylesheet {
*msg = NULL;
«@name»_t *_msg = NULL;
uper_decode_complete(NULL, &asn_DEF_«@name», (void **) &_msg, data, size);
if (!_msg)
asn_dec_rval_t rval = uper_decode_complete(NULL, &asn_DEF_«@name», (void **) &_msg, data, size);
// N.B: If you plan on having messages were the full message isn't consumed by decoding here,
// then please look into uper_decode_complete; we still may get a message, even if to contains
// nothing. RC_FAIL is an obvious case, but we also need to fail if RC_WMORE is the code, especially
// if rval.consumed == 0. Volker, please look into this and decide what you want.
if (!_msg || rval.code != RC_OK)
return PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
*msg = _msg;

@ -4,7 +4,7 @@
include yslt.yml2
tstylesheet {
template "protocol/fsm[count(state)>0]" document "{@name}.dot", "text"
template "/protocol/fsm[count(state)>0]"
||
digraph finite_state_machine {
rankdir=LR;

@ -1705,7 +1705,7 @@ tstylesheet {
switch (event) {
case None:
«../@name»_SERVICE_LOG("received Timeout event", "ignoring");
// received Timeout event, ignoring
break;
||

@ -18,8 +18,11 @@ system.db: create_system_db.sql $(DICOS)
.PHONY: install
install: system.db
mkdir -p $(DESTDIR)$(PER_MACHINE_DIRECTORY)
cp system.db $(DESTDIR)$(PER_MACHINE_DIRECTORY)
# Notice that the expansion of these make variables may still contain
# shell variable occurrences, to be expanded in their turn. This
# serves to leave more freedom to the deployment engineer.
mkdir -p "$(DESTDIR)$(PER_MACHINE_DIRECTORY)"
cp system.db "$(DESTDIR)$(PER_MACHINE_DIRECTORY)"
.PHONY: clean
clean:

@ -1,43 +1,56 @@
<!-- Copyright 2015-2017, pEp foundation, Switzerland
<!-- Copyright 2015-2021, pEp foundation, Switzerland
This file is part of the pEp Engine
This file may be used under the terms of the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) License
See CC_BY-SA.txt -->
# Build instructions for Debian 9
# Build instructions for Debian 9 and 10
We assume the user keeps sources under `~/pep-src`. There is no single
installation prefix: each package is built, or when supported installed, in
either its source directory or in a subdirectory of its source directory.
Rationale: we do not pollute the user system, uninstalling is trivial.
This is Unix: we assume no spaces in user names.
~~~
mkdir -p ~/pep-src
~~~
# Installing packaged dependencies
~~~
# general
apt install -y mercurial
# YML2
apt install -y python-lxml
apt install -y git
# libetpan
apt install -y git build-essential automake libtool
# asn1c
apt install -y git build-essential automake libtool autoconf
# sequoia
apt install git rustc cargo clang libclang-dev make pkg-config nettle-dev libssl-dev capnproto libsqlite3-dev
# engine
apt install -y uuid-dev libgpgme-dev libsqlite3-dev sqlite3
# optional: developer documentation
apt install -y doxygen pandoc
~~~
# Installing unpackaged dependencies
## YML2
~~~
mkdir -p ~/code/yml2
git clone https://gitea.pep.foundation/fdik/yml2.git ~/code/yml2
mkdir -p ~/pep-src/yml2
git clone https://gitea.pep.foundation/fdik/yml2.git ~/pep-src/yml2
~~~
## libetpan
pEp Engine requires libetpan with a set of patches that have not been upstreamed yet.
~~~
mkdir -p ~/code/libetpan
mkdir -p ~/pep-src/libetpan
git clone https://gitea.pep.foundation/pEp.foundation/libetpan.git ~/code/libetpan
cd ~/code/libetpan
mkdir ~/code/libetpan/build
./autogen.sh --prefix="$HOME/code/libetpan/build"
git clone https://gitea.pep.foundation/pEp.foundation/libetpan.git ~/pep-src/libetpan
cd ~/pep-src/libetpan
mkdir ~/pep-src/libetpan/build
./autogen.sh --prefix="$HOME/pep-src/libetpan/build"
make
make install
~~~
@ -45,45 +58,70 @@ make install
## asn1c
~~~
mkdir -p ~/code/asn1c
git clone git://github.com/vlm/asn1c.git ~/code/asn1c
cd ~/code/asn1c
mkdir -p ~/pep-src/asn1c
git clone git://github.com/vlm/asn1c.git ~/pep-src/asn1c
cd ~/pep-src/asn1c
git checkout tags/v0.9.28 -b pep-engine
autoreconf -iv
mkdir ~/code/asn1c/build
./configure --prefix="$HOME/code/asn1c/build"
mkdir ~/pep-src/asn1c/build
./configure --prefix="$HOME/pep-src/asn1c/build"
make
make install
~~~
## sequoia
~~~
git clone https://gitlab.com/sequoia-pgp/sequoia
cd ~/pep-src/sequoia
git checkout openpgp/v1.3.0
# Make an optimised sequoia build.
cargo build --all --release -j16
~~~
This alternative for the last line above is faster, but generates compiled libraries
in `~/pep-src/sequoia/target/debug` instead of `~/pep-src/sequoia/target/release`:
several definitions below need to be adapted.
~~~
# Alternative: make a debugging sequoia build.
cargo build --all -j16
~~~
# pEp Engine
~~~
mkdir -p ~/code/pep-engine
hg clone https://pep.foundation/dev/repos/pEpEngine/ ~/code/pep-engine
cd ~/code/pep-engine
mkdir ~/code/pep-engine/build
mkdir -p ~/pep-src/pep-engine
git clone https://gitea.pep.foundation/pEp.foundation/pEpEngine ~/pep-src/pep-engine
cd ~/pep-src/pep-engine
mkdir build
~~~
Edit the build configuration to your needs in `Makefile.conf`, or create a `local.conf` that sets any of the make variables documented in `Makefile.conf`. All the default values for the build configuration variables on each platform are documented in `Makefile.conf`.
Edit the build configuration to your needs in `Makefile.conf`, or create a `local.conf` in your source directory (the same containing `Makefile.conf`) that sets any of the make variables documented in `Makefile.conf`. All the default values for the build configuration variables on each platform are documented in `Makefile.conf`.
If a dependency is not found in your system's default include or library paths, you will have to specify the according paths in a make variable. Typically, this has to be done at least for YML2, libetpan and asn1c.
For a more detailed explanation of the mechanics of these build configuration files, and overriding defaults, see the comments in `Makefile.conf`.
Below is a sample `./local.conf` file, for orientation.
The following `./local.conf` example should work in the configuration described here.
~~~
PREFIX=$(HOME)/code/pep-engine/build
PREFIX=$(HOME)/pep-src/pep-engine/build
PER_MACHINE_DIRECTORY=$(PREFIX)/share/pEp
YML2_PATH=$(HOME)/code/yml2
YML2_PATH=$(HOME)/pep-src/yml2
ETPAN_LIB=-L$(HOME)/pep-src/libetpan/build/lib
ETPAN_INC=-I$(HOME)/pep-src/libetpan/build/include
ASN1C=$(HOME)/pep-src/asn1c/build/bin/asn1c
ASN1C_INC=-I$(HOME)/pep-src/asn1c/build/share/asn1c
ETPAN_LIB=-L$(HOME)/code/libetpan/build/lib
ETPAN_INC=-I$(HOME)/code/libetpan/build/include
SEQUOIA_INC=-I$(HOME)/pep-src/sequoia/openpgp-ffi/include
SEQUOIA_LDFLAGS=-L$(HOME)/pep-src/sequoia/target/release
ASN1C=$(HOME)/code/asn1c/build/bin/asn1c
ASN1C_INC=-I$(HOME)/code/asn1c/build/share/asn1c
GTEST_SRC_DIR=$(HOME)/pep-src/googletest/googletest
GTEST_INC_DIR=$(HOME)/pep-src/googletest/googletest/include
GTEST_PL=$(HOME)/pep-src/gtest-parallel/gtest_parallel.py
~~~
The engine is built as follows:

@ -22,7 +22,7 @@ endif
all: deps build
deps:
-docker pull $(IMAGE_NAME)-deps:latest
-docker pull --quiet $(IMAGE_NAME)-deps:latest
cd ../../ && docker build --build-arg CURRENT_DISTRO=$(CURRENT_DISTRO) \
--build-arg DOCKER_REGISTRY_HOST=${DOCKER_REGISTRY_HOST} \
--build-arg PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
@ -33,11 +33,14 @@ deps:
--tag=$(IMAGE_NAME)-deps:$(SEQUOIA_VERSION)-$(YML2_VERSION) \
--tag=$(IMAGE_NAME)-deps:latest \
-f scripts/${CURRENT_DISTRO}/deps.$(DOCKERFILE) .
docker push $(IMAGE_NAME)-deps:$(SEQUOIA_VERSION)-$(YML2_VERSION)
docker push $(IMAGE_NAME)-deps:latest
docker push --quiet $(IMAGE_NAME)-deps:$(SEQUOIA_VERSION)-$(YML2_VERSION)
docker push --quiet $(IMAGE_NAME)-deps:latest
build:
-docker pull $(IMAGE_NAME):latest
cd ../../ && /bin/sh ./scripts/common/build_pEpEngine.sh
build-docker:
-docker pull --quiet $(IMAGE_NAME):latest
cd ../../ && docker build --build-arg CURRENT_DISTRO=$(CURRENT_DISTRO) \
--build-arg DOCKER_REGISTRY_HOST=${DOCKER_REGISTRY_HOST} \
--build-arg PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
@ -47,12 +50,12 @@ build:
--cache-from $(IMAGE_NAME):latest \
--tag=$(IMAGE_NAME):$(PEPENGINE_VERSION) \
--tag=$(IMAGE_NAME):latest \
-f scripts/${CURRENT_DISTRO}/$(DOCKERFILE) .
docker push $(IMAGE_NAME):$(PEPENGINE_VERSION)
docker push $(IMAGE_NAME):latest
-f scripts/common/build.pEpEngine.Dockerfile .
docker push --quiet $(IMAGE_NAME):$(PEPENGINE_VERSION)
docker push --quiet $(IMAGE_NAME):latest
rpm:
-docker pull $(PKG_BUILD_IMAGE)-engine:latest
-docker pull --quiet $(PKG_BUILD_IMAGE)-engine:latest
@docker build --build-arg CURRENT_DISTRO=$(CURRENT_DISTRO) \
--build-arg PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
--build-arg DOCKER_REGISTRY_HOST=${DOCKER_REGISTRY_HOST} \
@ -62,8 +65,8 @@ rpm:
--tag=$(PKG_BUILD_IMAGE)-engine:$(PEPENGINE_VERSION) \
--tag=$(PKG_BUILD_IMAGE)-engine:latest \
packages/rpm
@docker push $(PKG_BUILD_IMAGE)-engine:$(PEPENGINE_VERSION)
@docker push $(PKG_BUILD_IMAGE)-engine:latest
@docker push --quiet $(PKG_BUILD_IMAGE)-engine:$(PEPENGINE_VERSION)
@docker push --quiet $(PKG_BUILD_IMAGE)-engine:latest
@docker run -e PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
-e PEP_MACHINE_DIR=$(PEP_MACHINE_DIR) \
-e PKG_VERSION=$(PEPENGINE_VERSION) \

@ -17,6 +17,9 @@ USER root
RUN yum install -y python3 python3-lxml binutils && yum clean all
### Setup PEP_MACHINE_DIR
RUN mkdir -p ${PEP_MACHINE_DIR}
RUN chown -R pep-builder:pep-builder ${BUILDROOT}/pEpEngine
WORKDIR ${BUILDROOT}/pEpEngine

@ -12,7 +12,8 @@ ARG PEP_MACHINE_DIR
### Setup working directory
USER root
RUN mkdir -p ${BUILDROOT}/pEpEngine
RUN rm -rf ${BUILDROOT}/pEpEngine && \
mkdir -p ${BUILDROOT}/pEpEngine
COPY . ${BUILDROOT}/pEpEngine
RUN chown -R pep-builder:pep-builder ${BUILDROOT}/pEpEngine

@ -6,6 +6,7 @@ SEQUOIA_VERSION=$(shell echo ${sequoia} | sed 's/\//-/')
CURRENT_DISTRO=$(shell basename $(shell pwd))
IMAGE_NAME=${DOCKER_REGISTRY_HOST}/pep-$(CURRENT_DISTRO)-engine
DOCKERFILE=pEpEngine.$(CURRENT_DISTRO).Dockerfile
PKG_INSTALL_PATH=/opt/pEp
IS_TAGGED=${TAGGED_BUILD}
ifeq ($(IS_TAGGED), true)
# $CI_COMMIT_TAG is a predefined environment variable from Gitlab
@ -13,10 +14,28 @@ ifeq ($(IS_TAGGED), true)
else
PEPENGINE_VERSION=$(shell git rev-parse --short=8 HEAD)
endif
all: build
all: deps build
deps:
-docker pull --quiet $(IMAGE_NAME)-deps:latest
cd ../../ && docker build --build-arg CURRENT_DISTRO=$(CURRENT_DISTRO) \
--build-arg DOCKER_REGISTRY_HOST=${DOCKER_REGISTRY_HOST} \
--build-arg PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
--build-arg SEQUOIA_VERSION=$(SEQUOIA_VERSION) \
--build-arg YML2_VERSION=$(YML2_VERSION) \
--build-arg PEP_MACHINE_DIR=$(PEP_MACHINE_DIR) \
--cache-from $(IMAGE_NAME):latest \
--tag=$(IMAGE_NAME)-deps:$(SEQUOIA_VERSION)-$(YML2_VERSION) \
--tag=$(IMAGE_NAME)-deps:latest \
-f scripts/${CURRENT_DISTRO}/deps.$(DOCKERFILE) .
docker push --quiet $(IMAGE_NAME)-deps:$(SEQUOIA_VERSION)-$(YML2_VERSION)
docker push --quiet $(IMAGE_NAME)-deps:latest
build:
-docker pull $(IMAGE_NAME):latest
cd ../../ && /bin/sh ./scripts/common/build_pEpEngine.sh
build-docker:
-docker pull --quiet $(IMAGE_NAME):latest
cd ../../ && docker build --build-arg CURRENT_DISTRO=$(CURRENT_DISTRO) \
--build-arg DOCKER_REGISTRY_HOST=${DOCKER_REGISTRY_HOST} \
--build-arg PEPENGINE_VERSION=$(PEPENGINE_VERSION) \
@ -26,6 +45,6 @@ build:
--cache-from $(IMAGE_NAME):latest \
--tag=$(IMAGE_NAME):$(PEPENGINE_VERSION) \
--tag=$(IMAGE_NAME):latest \
-f scripts/${CURRENT_DISTRO}/$(DOCKERFILE) .
docker push $(IMAGE_NAME):$(PEPENGINE_VERSION)
docker push $(IMAGE_NAME):latest
-f scripts/common/build.pEpEngine.Dockerfile .
docker push --quiet $(IMAGE_NAME):$(PEPENGINE_VERSION)
docker push --quiet $(IMAGE_NAME):latest

@ -11,10 +11,16 @@ ARG PEP_MACHINE_DIR
### Setup working directory
RUN mkdir ${BUILDROOT}/pEpEngine
COPY . ${BUILDROOT}/pEpEngine
COPY ./scripts/common/build_pEpEngine_deps.sh ${BUILDROOT}/pEpEngine
USER root
RUN apt-get update && apt-get install -y bzip2 && \
rm -rf /var/lib/apt/lists/*
### Setup PEP_MACHINE_DIR
RUN mkdir -p ${PEP_MACHINE_DIR}
RUN chown -R pep-builder:pep-builder ${BUILDROOT}/pEpEngine
WORKDIR ${BUILDROOT}/pEpEngine
@ -22,19 +28,7 @@ ARG YML2_VERSION
ARG ENGINE_VERSION
ARG CURRENT_DISTRO
RUN apt-get update && apt-get install -y bzip2 && \
rm -rf /var/lib/apt/lists/*
### Build pEpEngine dependencies
USER pep-builder
RUN sh ./scripts/common/build_pEpEngine_deps.sh
### Build pEpEngine
RUN sh ./scripts/common/build_pEpEngine.sh
### Install Systemdb
USER root
RUN sh ./scripts/common/install_pEpEngine_systemdb.sh && \
rm -rf ${BUILDROOT}/*
RUN sh ./build_pEpEngine_deps.sh

@ -5,11 +5,21 @@
include ../Makefile.conf
CFLAGS+= $(ETPAN_INC) $(PEP_MIME_INC) -I../asn.1 $(EXTRA_MACROS)
LDFLAGS+= $(ETPAN_LIB) $(PEP_MIME_LIB) -L../asn.1
# Notice the single quotes below: since user definitions can contain dollar
# signs it is important to prevent their expansion: shell variable references
# here must be expanded at run time, and not at compile time.
ifdef PER_USER_DIRECTORY
EXTRA_MACROS+= -DPER_USER_DIRECTORY='"$(PER_USER_DIRECTORY)"'
endif
ifdef PER_MACHINE_DIRECTORY
EXTRA_MACROS+= -DPER_MACHINE_DIRECTORY='"$(PER_MACHINE_DIRECTORY)"'
endif
ifneq ($(BUILD_ON),OS/390)
LDFLAGS+= -shared
endif
NO_SOURCE=
ifndef PEP_MIME
@ -113,17 +123,20 @@ clean:
rm -Rf $(TARGET).dSYM
rm -f KeySync_fsm.* Sync_actions.c Sync_event.* Sync_func.* Sync_impl.* sync_codec.* distribution_codec.* storage_codec.*
HEADERS_TO_INSTALL = \
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 group.h \
cryptotech.h sync_api.h pEp_string.h openpgp_compat.h engine_sql.h \
labeled_int_list.h key_reset.h base64.h sync_codec.h distribution_codec.h \
storage_codec.h status_to_string.h keyreset_command.h platform.h platform_unix.h \
transport.h growing_buf.h $(wildcard ../asn.1/*.h)
# CAVEAT:
# install_headers is needed for building *STANDALONE* pEp MIME - it is NOT used for built-in functionality!!!
install_headers: $(TARGET)
mkdir -p $(DESTDIR)$(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 group.h \
cryptotech.h sync_api.h pEp_string.h openpgp_compat.h engine_sql.h \
labeled_int_list.h key_reset.h base64.h sync_codec.h distribution_codec.h storage_codec.h \
status_to_string.h keyreset_command.h platform.h platform_unix.h ../asn.1/*.h \
$(DESTDIR)$(PREFIX)/include/pEp/
cp $(HEADERS_TO_INSTALL) $(DESTDIR)$(PREFIX)/include/pEp/
# FIXME: Does anyone but Roker use install_headers? Otherwise, remove the dependency.
install: $(TARGET) install_headers
@ -136,7 +149,8 @@ beinstall: install
uninstall:
rm -f $(DESTDIR)$(PREFIX)/lib/$(TARGET)
rm -rf $(DESTDIR)$(PREFIX)/include/pEp
rm $(addprefix $(DESTDIR)$(PREFIX)/include/pEp/,$(notdir $(HEADERS_TO_INSTALL)))
rmdir $(DESTDIR)$(PREFIX)/include/pEp 2> /dev/null || true
tags: $(wildcard *.c) $(wildcard *.h)
ctags --sort=yes *.c *.h

@ -713,7 +713,7 @@ static PEP_STATUS _create_core_tables(PEP_SESSION session) {
" timestamp integer default (datetime('now')),\n"
" primary key (address, user_id)\n"
");\n"
"create index if not exists identity_userid_addr on identity(address, user_id);\n"
"create index if not exists identity_userid on identity (user_id);\n"
"create table if not exists trust (\n"
" user_id text not null\n"
" references person (id)\n"
@ -1548,6 +1548,27 @@ static PEP_STATUS _upgrade_DB_to_ver_18(PEP_SESSION session) {
return _force_upgrade_own_latest_message_version(session);
}
static PEP_STATUS _upgrade_DB_to_ver_19(PEP_SESSION session) {
int int_result = sqlite3_exec(
session->db,
/* This index was useless: it was an index on the (multi-column)
primary key, always implemented using an index which gets also
used in queries. */
"drop index if exists identity_userid_addr;\n"
"\n"
"create index if not exists identity_userid on identity (user_id);\n",
NULL,
NULL,
NULL
);
assert(int_result == SQLITE_OK);
if (int_result != SQLITE_OK)
return PEP_UNKNOWN_DB_ERROR;
return PEP_STATUS_OK;
}
// Honestly, the upgrades should be redone in a transaction IMHO.
static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version) {
PEP_STATUS status = PEP_STATUS_OK;
@ -1620,6 +1641,10 @@ static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version)
if (status != PEP_STATUS_OK)
return status;
case 18:
status = _upgrade_DB_to_ver_19(session);
if (status != PEP_STATUS_OK)
return status;
case 19:
break;
default:
return PEP_ILLEGAL_VALUE;

@ -3,7 +3,7 @@
#include "pEp_internal.h"
// increment this when patching DDL
#define _DDL_USER_VERSION "18"
#define _DDL_USER_VERSION "19"
PEP_STATUS init_databases(PEP_SESSION session);
PEP_STATUS pEp_sql_init(PEP_SESSION session);

@ -875,13 +875,6 @@ DYNAMIC_API PEP_STATUS update_identity(
if (identity->comm_type == PEP_ct_unknown)
identity->comm_type = PEP_ct_key_not_found;
}
// VB says, and I quote, "that is not implemented and no one is using it right now"
// about this bit. So, um, you're forewarned.
if (identity->comm_type != PEP_ct_compromised &&
identity->comm_type < PEP_ct_strong_but_unconfirmed)
if (session->examine_identity)
session->examine_identity(identity, session->examine_management);
goto pEp_free;
@ -1256,66 +1249,6 @@ DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
return _myself(session, identity, true, true, false, false);
}
DYNAMIC_API PEP_STATUS register_examine_function(
PEP_SESSION session,
examine_identity_t examine_identity,
void *management
)
{
assert(session);
if (!session)
return PEP_ILLEGAL_VALUE;
session->examine_management = management;
session->examine_identity = examine_identity;
return PEP_STATUS_OK;
}
DYNAMIC_API PEP_STATUS do_keymanagement(
retrieve_next_identity_t retrieve_next_identity,
void *management
)
{
PEP_SESSION session;
pEp_identity *identity;
// FIXME_NOW: ensure_decrypt callback???
PEP_STATUS status = init(&session, NULL, NULL, NULL);
assert(!status);
if (status)
return status;
assert(session && retrieve_next_identity);
if (!(session && retrieve_next_identity))
return PEP_ILLEGAL_VALUE;
log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
while ((identity = retrieve_next_identity(management)))
{
assert(identity->address);
if(identity->address)
{
DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
if (identity->me) {
status = myself(session, identity);
} else {
status = recv_key(session, identity->address);
}
assert(status != PEP_OUT_OF_MEMORY);
if(status == PEP_OUT_OF_MEMORY)
return PEP_OUT_OF_MEMORY;
}
free_identity(identity);
}
log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
release(session);
return PEP_STATUS_OK;
}
DYNAMIC_API PEP_STATUS key_mistrusted(
PEP_SESSION session,
pEp_identity *ident

@ -122,92 +122,6 @@ DYNAMIC_API PEP_STATUS update_identity(
DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity);
/**
* <!-- retrieve_next_identity() -->
*
* @brief Callback being called by do_keymanagement()
*
* @param[in] management data structure to deliver (implementation defined)
*
* @retval identity to check or NULL to terminate do_keymanagement()
* if given identity must be created with new_identity()
* the identity struct is going to the ownership of this library
* it must not be freed by the callee
*
* @warning this callback has to block until an identity or NULL can be returned
* an implementation is not provided by this library; instead it has to be
* implemented by the user of this library
*
*/
typedef pEp_identity *(*retrieve_next_identity_t)(void *management);
/**
* <!-- examine_identity() -->
*
* @brief Callback for appending to queue
*
* @param[in] ident identity to examine
* @param[in] management data structure to deliver (implementation defined)
*
* @retval 0 if identity was added successfully to queue or nonzero otherwise
*
*
*/
typedef int (*examine_identity_t)(pEp_identity *ident, void *management);
/**
* <!-- register_examine_function() -->
*
* @brief Register examine_identity() callback
*
* @param[in] session session to use
* @param[in] examine_identity examine_identity() function to register
* @param[in] management data structure to deliver (implementation defined)
*
* @retval PEP_STATUS_OK
* @retval PEP_ILLEGAL_VALUE illegal parameter values
*
*/
DYNAMIC_API PEP_STATUS register_examine_function(
PEP_SESSION session,
examine_identity_t examine_identity,
void *management
);
/**
* <!-- do_keymanagement() -->
*
* @brief Function to be run on an extra thread
*
* @param[in] retrieve_next_identity pointer to retrieve_next_identity()
* callback which returns at least a valid
* address field in the identity struct
*
* @retval PEP_STATUS_OK if thread has to terminate successfully
* @retval PEP_ILLEGAL_VALUE illegal parameter values
* @retval PEP_OUT_OF_MEMORY out of memory
* @retval any other value on failure
*
* @warning to ensure proper working of this library, a thread has to be started
* with this function immediately after initialization
* do_keymanagement() calls retrieve_next_identity(management)
* messageToSend can only be null if no transport is application based
* if transport system is not used it must not be NULL
*
*/
DYNAMIC_API PEP_STATUS do_keymanagement(
retrieve_next_identity_t retrieve_next_identity,
void *management
);
/**
* <!-- key_mistrusted() -->
*

@ -131,8 +131,7 @@ IdentityList_t *IdentityList_from_identity_list(
{
bool allocated = !result;
assert(list);
if (!list)
if (!(list && list->ident))
return NULL;
if (allocated) {
@ -190,3 +189,902 @@ enomem:
return NULL;
}
PStringPair_t *PStringPair_from_Struct(
const stringpair_t *value,
PStringPair_t *result
)
{
bool allocated = !result;
assert(value);
if (!value)
return NULL;
if (allocated)
result = (PStringPair_t *) calloc(1, sizeof(PStringPair_t));
assert(result);
if (!result)
return NULL;
if (value->key) {
int r = OCTET_STRING_fromBuf(&result->key, value->key, -1);
if (r)
goto enomem;
}
if (value->value) {
int r = OCTET_STRING_fromBuf(&result->value, value->value, -1);
if (r)
goto enomem;
}
return result;
enomem:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PStringPair, result);
return NULL;
}
stringpair_t *PStringPair_to_Struct(PStringPair_t *value)
{
assert(value);
if (!value)
return NULL;
stringpair_t *result = (stringpair_t *) calloc(1, sizeof(stringpair_t));
assert(result);
if (!result)
goto enomem;
result->key = strndup((char *) value->key.buf,
value->key.size);
assert(result->key);
if (!result->key)
goto enomem;
result->value = strndup((char *) value->value.buf,
value->value.size);
assert(result->value);
if (!result->value)
goto enomem;
return result;
enomem:
free_stringpair(result);
return NULL;
}
PStringPairList_t *PStringPairList_from_stringpair_list(
const stringpair_list_t *list,
PStringPairList_t *result
)
{
bool allocated = !result;
assert(list);
if (!(list && list->value))
return NULL;
if (allocated) {
result = (PStringPairList_t *) calloc(1, sizeof(PStringPairList_t));
assert(result);
if (!result)
return NULL;
}
else {
asn_sequence_empty(result);
}
for (const stringpair_list_t *l = list; l && l->value; l=l->next) {
PStringPair_t *value = PStringPair_from_Struct(l->value, NULL);
if (ASN_SEQUENCE_ADD(&result->list, value)) {
ASN_STRUCT_FREE(asn_DEF_PStringPair, value);
goto enomem;
}
}
return result;
enomem:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PStringPairList, result);
return NULL;
}
stringpair_list_t *PStringPairList_to_stringpair_list(
PStringPairList_t *list,
stringpair_list_t *result
)
{
bool allocated = !result;
assert(list);
if (!list)
return NULL;
if (allocated)
result = new_stringpair_list(NULL);
if (!result)
return NULL;
stringpair_list_t *r = result;
for (int i=0; i<list->list.count; i++) {
stringpair_t *value = PStringPair_to_Struct(list->list.array[i]);
r = stringpair_list_add(r, value);
if (!r)
goto enomem;
}
return result;
enomem:
if (allocated)
free_stringpair_list(result);
return NULL;
}
PStringList_t *PStringList_from_stringlist(
const stringlist_t *list,
PStringList_t *result
)
{
bool allocated = !result;
assert(list);
if (!(list && list->value))
return NULL;
if (allocated) {
result = (PStringList_t *) calloc(1, sizeof(PStringList_t));
assert(result);
if (!result)
return NULL;
}
else {
asn_sequence_empty(result);
}
for (const stringlist_t *l = list; l && l->value; l=l->next) {
PString_t *element = (PString_t *) calloc(1, sizeof(PString_t));
assert(element);
if (!element)
goto enomem;
int r = OCTET_STRING_fromBuf(element, l->value, -1);
if (r)
goto enomem;
if (ASN_SEQUENCE_ADD(&result->list, element)) {
ASN_STRUCT_FREE(asn_DEF_PString, element);
goto enomem;
}
}
return result;
enomem:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PStringList, result);
return NULL;
}
stringlist_t *PStringList_to_stringlist(PStringList_t *list)
{
assert(list);
if (!list)
return NULL;
stringlist_t *result = (stringlist_t *) calloc(1, sizeof(stringlist_t));
assert(result);
if (!result)
goto enomem;
stringlist_t *r = result;
for (int i=0; i<list->list.count; i++) {
char *s = strndup((char *) list->list.array[i]->buf,
list->list.array[i]->size);
assert(s);
if (!s)
goto enomem;
r->value = s;
if (i < list->list.count-1) {
r->next = (stringlist_t *) calloc(1, sizeof(stringlist_t));
assert(r->next);
if (!r->next)
goto enomem;
r = r->next;
}
}
return result;
enomem:
free_stringlist(result);
return NULL;
}
PBlobList_t *PBlobList_from_bloblist(
bloblist_t *list,
PBlobList_t *result,
bool copy,
size_t max_blob_size
)
{
bool allocated = !result;
if (!max_blob_size)
max_blob_size = SIZE_MAX;
assert(list);
if (!(list && list->value))
return NULL;
if (allocated) {
result = (PBlobList_t *) calloc(1, sizeof(PBlobList_t));
assert(result);
if (!result)
return NULL;
}
else {
asn_sequence_empty(result);
}
size_t rest_blob_size = max_blob_size;
for (bloblist_t *l = list; l && l->value; l=l->next) {
PBlob_t *element = (PBlob_t *) calloc(1, sizeof(PBlob_t));
assert(element);
if (!element)
goto enomem;
int r = 0;
if (l->size > rest_blob_size)
goto enomem;
rest_blob_size -= l->size;
if (copy) {
r = OCTET_STRING_fromBuf(&element->value, l->value, l->size);
if (r)
goto enomem;
}
else /* move */ {
#if defined(__CHAR_BIT__) && __CHAR_BIT__ == 8
element->value.buf = (uint8_t *) l->value;
#else
// FIXME: this is problematic on platforms with bytes != octets
// we want this warning
element->value.buf = l->value;
#endif
l->value = NULL;
element->value.size = l->size;
l->size = 0;
}
if (!EMPTYSTR(l->mime_type)) {
PString_t *_mime_type = (PString_t *) calloc(1, sizeof(PString_t));
assert(_mime_type);
if (!_mime_type)
goto enomem;
r = OCTET_STRING_fromBuf(_mime_type, l->mime_type, -1);
if (r)
goto enomem;
element->mime_type = _mime_type;
}
if (!EMPTYSTR(l->filename)) {
PString_t *_filename = (PString_t *) calloc(1, sizeof(PString_t));
assert(_filename);
if (!_filename)
goto enomem;
r = OCTET_STRING_fromBuf(_filename, l->filename, -1);
if (r)
goto enomem;
element->filename = _filename;
}
switch (l->disposition) {
case PEP_CONTENT_DISP_ATTACHMENT:
element->disposition = ContentDisposition_attachment;
break;
case PEP_CONTENT_DISP_INLINE:
element->disposition = ContentDisposition_inline;
break;
case PEP_CONTENT_DISP_OTHER:
element->disposition = ContentDisposition_other;
break;
default:
assert(0); // should not happen; use default
element->disposition = ContentDisposition_attachment;
}
if (ASN_SEQUENCE_ADD(&result->list, element)) {
ASN_STRUCT_FREE(asn_DEF_PBlob, element);
goto enomem;
}
}
return result;
enomem:
if (allocated)
ASN_STRUCT_FREE(asn_DEF_PBlobList, result);
return NULL;
}
bloblist_t *PBlobList_to_bloblist(
PBlobList_t *list,
bloblist_t *result,
bool copy,
size_t max_blob_size
)
{
bool allocated = !result;
if (!max_blob_size)
max_blob_size = SIZE_MAX;
assert(list);
if (!list)
return NULL;
if (allocated)
result = new_bloblist(NULL, 0, NULL, NULL);
if (!result)
return NULL;
size_t rest_blob_size = max_blob_size;
bloblist_t *r = result;
for (int i=0; i<list->list.count; i++) {
// this should not happen
assert(list->list.array[i]);
if (!list->list.array[i])
goto enomem;
if (list->list.array[i]->value.size > rest_blob_size)
goto enomem;
rest_blob_size -= list->list.array[i]->value.size;
char *_mime_type = NULL;
if (list->list.array[i]->mime_type) {
_mime_type = strndup((char *) list->list.array[i]->mime_type->buf,
list->list.array[i]->mime_type->size);
assert(_mime_type);
if (!_mime_type)
goto enomem;
}
char *_filename = NULL;
if (list->list.array[i]->filename) {
_filename = strndup((char *) list->list.array[i]->filename->buf,
list->list.array[i]->filename->size);
assert(_filename);
if (!_filename)
goto enomem;
}
#if defined(__CHAR_BIT__) && __CHAR_BIT__ == 8
char *_data = (char *) list->list.array[i]->value.buf;
#else
// FIXME: this is problematic on platforms with bytes != octets
// we want this warning
char *_data = list->list.array[i]->value.buf;
#endif
if (copy) {
_data = strndup(_data, list->list.array[i]->value.size);
assert(_data);
if (!_data)
goto enomem;
}
// bloblist_add() has move semantics
r = bloblist_add(r, _data, list->list.array[i]->value.size, _mime_type,
_filename);
if (!copy) {
list->list.array[i]->value.buf = NULL;
list->list.array[i]->value.size = 0;
}