Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d190060e | ||
|
|
1f299c7a1a | ||
|
|
74cfb901fd | ||
|
|
065fd5d9b5 | ||
|
|
bf547dd3fe | ||
|
|
81e47c59cd | ||
|
|
7862cda661 | ||
|
|
329552030b | ||
|
|
04904d8c61 | ||
|
|
f0b4a05c70 | ||
|
|
95d6911f1a | ||
|
|
48f98ef34e | ||
|
|
ae0c5eae77 | ||
|
|
0c2d727057 | ||
|
|
072f5f5a15 | ||
|
|
1db85743a0 | ||
|
|
2cf66e037d | ||
|
|
449d838dc2 | ||
|
|
c4bc215a47 | ||
|
|
c9936d7ecf | ||
|
|
885e59a2af | ||
|
|
bf398889bf | ||
|
|
e26e3d7307 | ||
|
|
045b275b27 | ||
|
|
7ec1973e0f | ||
|
|
a79a9c4eff | ||
|
|
f049e2430a | ||
|
|
59b3219f2d | ||
|
|
e9eb8bdc86 | ||
|
|
5e0c7ae4f2 | ||
|
|
c1c0c1ab44 | ||
|
|
a59fff785b | ||
|
|
6a70db80e6 | ||
|
|
d610630c8d | ||
|
|
4dc7790015 | ||
|
|
9dd000a2ca | ||
|
|
ce4084e528 |
No files matched your search
@@ -1,163 +0,0 @@
|
||||
FROM ubuntu:noble
|
||||
|
||||
# The standard user with which vscode-server will be executed
|
||||
ARG USERNAME=sogo
|
||||
ARG USER_ID=1000 GROUP_ID=1000
|
||||
|
||||
ENV CONTAINER_USERNAME=${USERNAME}
|
||||
|
||||
# rename user ubuntu to ${USERNAME}
|
||||
RUN usermod -l ${CONTAINER_USERNAME} ubuntu && groupmod -n ${CONTAINER_USERNAME} ubuntu
|
||||
|
||||
RUN apt-get update && apt-get install -y sudo \
|
||||
&& usermod -aG sudo ${CONTAINER_USERNAME} \
|
||||
&& echo ${CONTAINER_USERNAME} ALL=\(ALL\) NOPASSWD:ALL > /etc/sudoers.d/${CONTAINER_USERNAME} \
|
||||
&& chmod 0440 /etc/sudoers.d/${CONTAINER_USERNAME}
|
||||
|
||||
# Ensure sudo group users are not asked for a password
|
||||
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/${CONTAINER_USERNAME} && chmod 0440 /etc/sudoers.d/${CONTAINER_USERNAME}
|
||||
|
||||
ENV WORKSPACE=/workspace
|
||||
RUN mkdir -p ${WORKSPACE} && chown -R ${CONTAINER_USERNAME}:${CONTAINER_USERNAME} ${WORKSPACE}
|
||||
|
||||
RUN apt-get clean && apt-get update --allow-unauthenticated --allow-insecure-repositories \
|
||||
&& apt-get install -y --fix-missing git cmake libexpat-dev curl telnet nano
|
||||
|
||||
|
||||
WORKDIR /tmp/build
|
||||
|
||||
RUN mkdir -p /src/libwbxml && mkdir -p /tmp/build/libwbxml
|
||||
RUN git clone https://github.com/libwbxml/libwbxml.git /src/libwbxml/
|
||||
RUN cmake -B/tmp/build/libwbxml -DCMAKE_INSTALL_PREFIX=$prefix /src/libwbxml && cd /tmp/build/libwbxml && make && make install
|
||||
# For backward compatibility
|
||||
|
||||
WORKDIR ${WORKSPACE}
|
||||
|
||||
RUN ln -s /include/libwbxml-1.1 /usr/include/libwbxml-1.0
|
||||
RUN ln -s /include/libwbxml-1.1 /usr/include/libwbxml
|
||||
RUN ln -s /include/libwbxml-1.1 /usr/include/libwbxml-1.1
|
||||
|
||||
# download, prepare & compile
|
||||
RUN echo "Download SOPE sources" \
|
||||
&& git clone https://github.com/Alinto/sope.git /src/SOPE \
|
||||
&& echo "install required packages" \
|
||||
&& apt-get update \
|
||||
&& apt-get upgrade --allow-unauthenticated -qy \
|
||||
&& DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install --allow-unauthenticated -qy --no-install-recommends \
|
||||
gnustep-make \
|
||||
gnustep-base-runtime \
|
||||
libgnustep-base-dev \
|
||||
pkg-config \
|
||||
make \
|
||||
gobjc \
|
||||
g++ \
|
||||
gdb gdbserver \
|
||||
vim \
|
||||
liblasso3-dev \
|
||||
python-is-python3 \
|
||||
libz-dev \
|
||||
zlib1g-dev \
|
||||
libpq-dev \
|
||||
libmysqlclient-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libsodium-dev \
|
||||
libxml2-dev \
|
||||
libssl-dev \
|
||||
libldap2-dev \
|
||||
libzip-dev \
|
||||
mariadb-client \
|
||||
postgresql-client \
|
||||
tmpreaper \
|
||||
python3-m2crypto \
|
||||
python3-simplejson \
|
||||
python3-vobject \
|
||||
python3-dateutil \
|
||||
postgresql-server-dev-all \
|
||||
libmemcached-dev \
|
||||
libcurl4-openssl-dev \
|
||||
tzdata \
|
||||
libytnef0 \
|
||||
libytnef0-dev \
|
||||
liboath-dev \
|
||||
sudo \
|
||||
lsof \
|
||||
systemd \
|
||||
tcpdump \
|
||||
jq libxml2-utils
|
||||
|
||||
RUN echo "compiling sope" \
|
||||
&& cd /src/SOPE \
|
||||
&& ./configure --with-gnustep --enable-debug --disable-strip \
|
||||
&& make \
|
||||
&& make install
|
||||
|
||||
# copy sogo local sources
|
||||
COPY / /src/SOGo
|
||||
RUN chown -R ${CONTAINER_USERNAME}:${CONTAINER_USERNAME} /src/SOGo
|
||||
|
||||
# install sogo
|
||||
RUN echo "compiling sogo"
|
||||
|
||||
# RUN chmod +x /src/SOGo/configure
|
||||
WORKDIR /src/SOGo
|
||||
RUN ./configure --enable-debug --disable-strip --enable-mfa
|
||||
RUN make
|
||||
RUN make install
|
||||
RUN echo "register sogo library"
|
||||
RUN echo "/usr/local/lib/sogo" > /etc/ld.so.conf.d/sogo.conf
|
||||
RUN ldconfig
|
||||
RUN echo "create directories and enforce permissions"
|
||||
RUN install -o sogo -g sogo -m 755 -d /var/run/sogo
|
||||
RUN install -o sogo -g sogo -m 750 -d /var/spool/sogo
|
||||
RUN install -o sogo -g sogo -m 750 -d /var/log/sogo
|
||||
|
||||
WORKDIR ${WORKSPACE}
|
||||
|
||||
# Copy the binary file into /usr/local/bin
|
||||
COPY .devcontainer/conf/sogo/compile_sogo.sh /usr/local/bin/compile_sogo.sh
|
||||
# Set the appropriate permissions
|
||||
RUN chmod +x /usr/local/bin/compile_sogo.sh
|
||||
|
||||
# Install nodejs
|
||||
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -
|
||||
RUN apt install -qy nodejs \
|
||||
&& npm i -g grunt
|
||||
|
||||
# Users
|
||||
RUN useradd sogo-tests1 && \
|
||||
useradd sogo-tests2 && \
|
||||
useradd sogo-tests3 && \
|
||||
useradd sogo-tests-super
|
||||
|
||||
# Tests
|
||||
RUN npm i -g xunit-viewer
|
||||
|
||||
|
||||
# SOGo
|
||||
RUN apt-get clean && apt-get install -y --no-install-recommends wget && cd /tmp && \
|
||||
wget https://raw.githubusercontent.com/Alinto/sogo/master/packaging/debian/sogo.init && \
|
||||
ln -s /usr/local/sbin/sogod /usr/sbin/sogod && \
|
||||
mv sogo.init /etc/init.d/sogod && chmod +x /etc/init.d/sogod && \
|
||||
mkdir /etc/sogo
|
||||
COPY .devcontainer/conf/sogo/sogo.conf /etc/sogo/
|
||||
ADD .devcontainer/conf/sogo/sogo.conf /etc/sogo/sogo-base.conf
|
||||
|
||||
# Clean
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Dev env script
|
||||
ADD .devcontainer/conf/sogo/devenv /usr/sbin/
|
||||
ADD .devcontainer/conf/sogo/common.sh /include/
|
||||
RUN chmod +x /usr/sbin/devenv
|
||||
RUN chmod +x /include/common.sh
|
||||
|
||||
# Interface the environment
|
||||
EXPOSE 50000 50001
|
||||
|
||||
# Entrypoint
|
||||
ADD .devcontainer/conf/sogo/entrypoint.sh /
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
USER ${CONTAINER_USERNAME}
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
@@ -1,67 +0,0 @@
|
||||
CREATE USER IF NOT EXISTS 'sogobuild'@'%' IDENTIFIED BY 'sogo123';
|
||||
GRANT ALL PRIVILEGES ON * . * TO 'sogobuild'@'%';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS sogo;
|
||||
USE sogo;
|
||||
-- INSERT INTO
|
||||
CREATE DATABASE IF NOT EXISTS sogo_integration_tests_auth;
|
||||
USE sogo_integration_tests_auth;
|
||||
-- MySQL dump 10.16 Distrib 10.1.48-MariaDB, for debian-linux-gnu (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: sogo_integration_tests_auth
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.1.48-MariaDB-0+deb9u2
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sogoauth`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sogoauth`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `sogoauth` (
|
||||
`c_uid` varchar(255) NOT NULL,
|
||||
`c_name` varchar(255) NOT NULL,
|
||||
`c_password` varchar(255) DEFAULT NULL,
|
||||
`c_cn` varchar(255) DEFAULT NULL,
|
||||
`mail` varchar(255) DEFAULT NULL,
|
||||
`kind` varchar(255) DEFAULT NULL,
|
||||
`multiplebookings` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`c_uid`),
|
||||
UNIQUE KEY `c_name` (`c_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sogoauth`
|
||||
--
|
||||
|
||||
LOCK TABLES `sogoauth` WRITE;
|
||||
/*!40000 ALTER TABLE `sogoauth` DISABLE KEYS */;
|
||||
INSERT INTO `sogoauth` VALUES ('res','res','sogo','Resource no overbook','res@example.org','location',1),('res-nolimit','res-nolimit','sogo','Resource can overbook','res-nolimit@example.org','location',0),('sogo-tests-super','sogo-tests-super','sogo','sogo test super','sogo-tests-super@example.org',NULL,NULL),('sogo-tests1','sogo-tests1','sogo','sogo One','sogo-tests1@example.org',NULL,NULL),('sogo-tests2','sogo-tests2','sogo','sogo Two','sogo-tests2@example.org',NULL,NULL),('sogo-tests3','sogo-tests3','sogo','sogo Three','sogo-tests3@example.org',NULL,NULL);
|
||||
/*!40000 ALTER TABLE `sogoauth` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2023-02-22 4:15:31
|
||||
@@ -1,72 +0,0 @@
|
||||
# From https://github.com/dovecot/docker/blob/main/2.3.21.1/
|
||||
FROM debian:11-slim
|
||||
|
||||
LABEL org.opencontainers.image.authors="dovecot@dovecot.org"
|
||||
|
||||
ENV container=docker \
|
||||
LC_ALL=C
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ADD dovecot.gpg /etc/apt/keyrings/dovecot.gpg
|
||||
ADD dovecot.list /etc/apt/sources.list.d
|
||||
|
||||
RUN apt-get -y update && apt-get -y install \
|
||||
tini \
|
||||
dovecot-core \
|
||||
dovecot-gssapi \
|
||||
dovecot-imapd \
|
||||
dovecot-ldap \
|
||||
dovecot-lmtpd \
|
||||
dovecot-managesieved \
|
||||
dovecot-mysql \
|
||||
dovecot-pgsql \
|
||||
dovecot-pop3d \
|
||||
dovecot-sieve \
|
||||
dovecot-solr \
|
||||
dovecot-sqlite \
|
||||
dovecot-submissiond \
|
||||
ca-certificates \
|
||||
ssl-cert && \
|
||||
rm -rf /var/lib/apt/lists && \
|
||||
groupadd -g 1000 vmail && \
|
||||
useradd -u 1000 -g 1000 vmail -d /srv/vmail && \
|
||||
passwd -l vmail && \
|
||||
rm -rf /etc/dovecot && \
|
||||
mkdir /srv/mail && \
|
||||
chown vmail:vmail /srv/mail && \
|
||||
make-ssl-cert generate-default-snakeoil && \
|
||||
mkdir /etc/dovecot && \
|
||||
ln -s /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/dovecot/cert.pem && \
|
||||
ln -s /etc/ssl/private/ssl-cert-snakeoil.key /etc/dovecot/key.pem
|
||||
|
||||
#ADD dovecot.conf /etc/dovecot/dovecot.conf
|
||||
|
||||
# Add for SOGo env
|
||||
RUN apt-get update --allow-insecure-repositories && \
|
||||
apt-get install --allow-unauthenticated -y dovecot-ldap dovecot-sieve dovecot-managesieved dovecot-lmtpd
|
||||
|
||||
RUN chown -R dovecot:dovecot /var/mail
|
||||
RUN mkdir /var/sieve && \
|
||||
chmod -R 755 /var/sieve && \
|
||||
chown -R vmail:vmail /var/sieve
|
||||
|
||||
ADD dovecot.conf /etc/dovecot/dovecot.conf
|
||||
ADD conf.d /etc/dovecot/conf.d
|
||||
ADD dovecot-ldap.conf.ext /etc/dovecot/dovecot-ldap.conf.ext
|
||||
# Clean
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
# End add for SOGo env
|
||||
|
||||
ADD wait-for-it.sh /wait-for-it.sh
|
||||
|
||||
EXPOSE 24
|
||||
EXPOSE 110
|
||||
EXPOSE 143
|
||||
EXPOSE 587
|
||||
EXPOSE 990
|
||||
EXPOSE 993
|
||||
EXPOSE 4190
|
||||
|
||||
VOLUME ["/etc/dovecot", "/srv/mail"]
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
CMD ["./wait-for-it.sh", "openldap:389", "--", "/usr/sbin/dovecot", "-F"]
|
||||
@@ -1,3 +0,0 @@
|
||||
disable_plaintext_auth = no
|
||||
auth_mechanisms = plain login
|
||||
!include auth-ldap.conf.ext
|
||||
@@ -1,11 +0,0 @@
|
||||
mail_location = maildir:/var/mail/%n
|
||||
namespace inbox {
|
||||
inbox = yes
|
||||
}
|
||||
mail_privileged_group = mail
|
||||
protocol !indexer-worker {
|
||||
}
|
||||
|
||||
protocol imap {
|
||||
mail_plugins = $mail_plugins acl
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
service imap-login {
|
||||
inet_listener imap {
|
||||
#port = 143
|
||||
}
|
||||
inet_listener imaps {
|
||||
#port = 993
|
||||
#ssl = yes
|
||||
}
|
||||
}
|
||||
|
||||
service pop3-login {
|
||||
inet_listener pop3 {
|
||||
#port = 110
|
||||
}
|
||||
inet_listener pop3s {
|
||||
#port = 995
|
||||
#ssl = yes
|
||||
}
|
||||
}
|
||||
|
||||
service submission-login {
|
||||
inet_listener submission {
|
||||
#port = 587
|
||||
}
|
||||
}
|
||||
|
||||
service lmtp {
|
||||
unix_listener /var/spool/dovecot-lmtp {
|
||||
mode = 0660
|
||||
user = root
|
||||
group = root
|
||||
}
|
||||
inet_listener lmtp {
|
||||
port = 24
|
||||
}
|
||||
}
|
||||
|
||||
service imap {
|
||||
# Most of the memory goes to mmap()ing files. You may need to increase this
|
||||
# limit if you have huge mailboxes.
|
||||
#vsz_limit = $default_vsz_limit
|
||||
|
||||
# Max. number of IMAP processes (connections)
|
||||
#process_limit = 1024
|
||||
}
|
||||
|
||||
service pop3 {
|
||||
# Max. number of POP3 processes (connections)
|
||||
#process_limit = 1024
|
||||
}
|
||||
|
||||
service submission {
|
||||
# Max. number of SMTP Submission processes (connections)
|
||||
#process_limit = 1024
|
||||
}
|
||||
|
||||
service auth {
|
||||
unix_listener auth-userdb {
|
||||
#mode = 0666
|
||||
#user =
|
||||
#group =
|
||||
}
|
||||
|
||||
# Postfix smtp-auth
|
||||
#unix_listener /var/spool/postfix/private/auth {
|
||||
# mode = 0666
|
||||
#}
|
||||
|
||||
# Auth process is run as this user.
|
||||
#user = $default_internal_user
|
||||
}
|
||||
|
||||
service auth-worker {
|
||||
# Auth worker process is run as root by default, so that it can access
|
||||
# /etc/shadow. If this isn't necessary, the user should be changed to
|
||||
# $default_internal_user.
|
||||
#user = root
|
||||
}
|
||||
|
||||
service dict {
|
||||
# If dict proxy is used, mail processes should have access to its socket.
|
||||
# For example: mode=0660, group=vmail and global mail_access_groups=vmail
|
||||
unix_listener dict {
|
||||
#mode = 0600
|
||||
#user =
|
||||
#group =
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
protocol lmtp {
|
||||
postmaster_address = postmaster@example.org
|
||||
# Space separated list of plugins to load (default is global mail_plugins).
|
||||
mail_plugins = $mail_plugins sieve
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
plugin {
|
||||
acl = vfile
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
plugin {
|
||||
sieve = file:/var/sieve/%n@example.org;active=/var/sieve/%n@example.org/.dovecot.sieve
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
passdb {
|
||||
driver = ldap
|
||||
|
||||
# Path for LDAP configuration file, see example-config/dovecot-ldap.conf.ext
|
||||
args = /etc/dovecot/dovecot-ldap.conf.ext
|
||||
}
|
||||
|
||||
userdb {
|
||||
driver = ldap
|
||||
args = /etc/dovecot/dovecot-ldap.conf.ext
|
||||
|
||||
# Default fields can be used to specify defaults that LDAP may override
|
||||
#default_fields = home=/home/virtual/%u
|
||||
}
|
||||
|
||||
mail_gid = 8
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
hosts = openldap:389
|
||||
dn = cn=admin,dc=example,dc=org
|
||||
dnpass = password
|
||||
debug_level = -1
|
||||
auth_bind = yes
|
||||
ldap_version = 3
|
||||
base = ou=users,dc=example,dc=org
|
||||
user_filter = (&(objectClass=posixAccount)(uid=%u))
|
||||
user_filter = (|(uid=%u)(mail=%u))
|
||||
@@ -1,13 +0,0 @@
|
||||
## Dovecot configuration file
|
||||
|
||||
!include_try /usr/share/dovecot/protocols.d/*.protocol
|
||||
!include conf.d/*.conf
|
||||
protocols = imap lmtp sieve
|
||||
!include_try local.conf
|
||||
|
||||
log_path = /dev/stderr
|
||||
auth_verbose = yes
|
||||
auth_debug = yes
|
||||
mail_debug = yes
|
||||
|
||||
mail_plugins = acl
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
deb [signed-by=/etc/apt/keyrings/dovecot.gpg] http://repo.dovecot.org/ce-2.3.21.1/debian/bullseye bullseye main
|
||||
@@ -1,182 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Use this script to test if a given TCP host/port are available
|
||||
|
||||
WAITFORIT_cmdname=${0##*/}
|
||||
|
||||
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << USAGE >&2
|
||||
Usage:
|
||||
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
|
||||
-h HOST | --host=HOST Host or IP under test
|
||||
-p PORT | --port=PORT TCP port under test
|
||||
Alternatively, you specify the host and port as host:port
|
||||
-s | --strict Only execute subcommand if the test succeeds
|
||||
-q | --quiet Don't output any status messages
|
||||
-t TIMEOUT | --timeout=TIMEOUT
|
||||
Timeout in seconds, zero for no timeout
|
||||
-- COMMAND ARGS Execute command with args after the test finishes
|
||||
USAGE
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
||||
else
|
||||
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
|
||||
fi
|
||||
WAITFORIT_start_ts=$(date +%s)
|
||||
while :
|
||||
do
|
||||
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
|
||||
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
|
||||
WAITFORIT_result=$?
|
||||
else
|
||||
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
|
||||
WAITFORIT_result=$?
|
||||
fi
|
||||
if [[ $WAITFORIT_result -eq 0 ]]; then
|
||||
WAITFORIT_end_ts=$(date +%s)
|
||||
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return $WAITFORIT_result
|
||||
}
|
||||
|
||||
wait_for_wrapper()
|
||||
{
|
||||
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
|
||||
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
|
||||
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
||||
else
|
||||
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
||||
fi
|
||||
WAITFORIT_PID=$!
|
||||
trap "kill -INT -$WAITFORIT_PID" INT
|
||||
wait $WAITFORIT_PID
|
||||
WAITFORIT_RESULT=$?
|
||||
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
||||
fi
|
||||
return $WAITFORIT_RESULT
|
||||
}
|
||||
|
||||
# process arguments
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
*:* )
|
||||
WAITFORIT_hostport=(${1//:/ })
|
||||
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
|
||||
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
|
||||
shift 1
|
||||
;;
|
||||
--child)
|
||||
WAITFORIT_CHILD=1
|
||||
shift 1
|
||||
;;
|
||||
-q | --quiet)
|
||||
WAITFORIT_QUIET=1
|
||||
shift 1
|
||||
;;
|
||||
-s | --strict)
|
||||
WAITFORIT_STRICT=1
|
||||
shift 1
|
||||
;;
|
||||
-h)
|
||||
WAITFORIT_HOST="$2"
|
||||
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--host=*)
|
||||
WAITFORIT_HOST="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-p)
|
||||
WAITFORIT_PORT="$2"
|
||||
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--port=*)
|
||||
WAITFORIT_PORT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-t)
|
||||
WAITFORIT_TIMEOUT="$2"
|
||||
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--timeout=*)
|
||||
WAITFORIT_TIMEOUT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
WAITFORIT_CLI=("$@")
|
||||
break
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echoerr "Unknown argument: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
|
||||
echoerr "Error: you need to provide a host and port to test."
|
||||
usage
|
||||
fi
|
||||
|
||||
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
|
||||
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
|
||||
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
|
||||
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
|
||||
|
||||
# Check to see if timeout is from busybox?
|
||||
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
|
||||
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
|
||||
|
||||
WAITFORIT_BUSYTIMEFLAG=""
|
||||
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
|
||||
WAITFORIT_ISBUSY=1
|
||||
# Check if busybox timeout uses -t flag
|
||||
# (recent Alpine versions don't support -t anymore)
|
||||
if timeout &>/dev/stdout | grep -q -e '-t '; then
|
||||
WAITFORIT_BUSYTIMEFLAG="-t"
|
||||
fi
|
||||
else
|
||||
WAITFORIT_ISBUSY=0
|
||||
fi
|
||||
|
||||
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
|
||||
wait_for
|
||||
WAITFORIT_RESULT=$?
|
||||
exit $WAITFORIT_RESULT
|
||||
else
|
||||
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
||||
wait_for_wrapper
|
||||
WAITFORIT_RESULT=$?
|
||||
else
|
||||
wait_for
|
||||
WAITFORIT_RESULT=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $WAITFORIT_CLI != "" ]]; then
|
||||
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
|
||||
exit $WAITFORIT_RESULT
|
||||
fi
|
||||
exec "${WAITFORIT_CLI[@]}"
|
||||
else
|
||||
exit $WAITFORIT_RESULT
|
||||
fi
|
||||
@@ -1,277 +0,0 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:America/Denver
|
||||
X-LIC-LOCATION:America/Denver
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:-0700
|
||||
TZOFFSETTO:-0600
|
||||
TZNAME:MDT
|
||||
DTSTART:19700308T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:-0600
|
||||
TZOFFSETTO:-0700
|
||||
TZNAME:MST
|
||||
DTSTART:19701101T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T215905Z
|
||||
LAST-MODIFIED:20120117T215919Z
|
||||
DTSTAMP:20120117T215919Z
|
||||
UID:58f2f5bb-3be9-43d5-998b-088c593dbc85
|
||||
SUMMARY:New Year's Day
|
||||
DTSTART;TZID=America/Denver:20120101T081500
|
||||
DTEND;TZID=America/Denver:20120101T090500
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T215933Z
|
||||
LAST-MODIFIED:20120117T215941Z
|
||||
DTSTAMP:20120117T215941Z
|
||||
UID:7fdfe99e-3485-4af4-8949-2b0c8c829d17
|
||||
SUMMARY:Epiphany
|
||||
DTSTART;VALUE=DATE:20120106
|
||||
DTEND;VALUE=DATE:20120107
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T215959Z
|
||||
LAST-MODIFIED:20120117T220007Z
|
||||
DTSTAMP:20120117T220007Z
|
||||
UID:112cd226-2600-48d3-b5e8-55ab497c7a10
|
||||
SUMMARY:Groundhog Day
|
||||
DTSTART;VALUE=DATE:20120202
|
||||
DTEND;VALUE=DATE:20120203
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220032Z
|
||||
LAST-MODIFIED:20120117T220040Z
|
||||
DTSTAMP:20120117T220040Z
|
||||
UID:42daa2c5-42e0-4cbc-a614-1284b2f3378b
|
||||
SUMMARY:Valentine's Day
|
||||
DTSTART;VALUE=DATE:20120214
|
||||
DTEND;VALUE=DATE:20120215
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220145Z
|
||||
LAST-MODIFIED:20120117T220156Z
|
||||
DTSTAMP:20120117T220156Z
|
||||
UID:d35c66b7-cc8f-4fa8-b980-eae06732a679
|
||||
SUMMARY:St. Patrick's Day
|
||||
DTSTART;VALUE=DATE:20120317
|
||||
DTEND;VALUE=DATE:20120318
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220208Z
|
||||
LAST-MODIFIED:20120117T220215Z
|
||||
DTSTAMP:20120117T220215Z
|
||||
UID:15440c4b-f459-4599-9d92-5906555eb6d1
|
||||
SUMMARY:Good Friday
|
||||
DTSTART;VALUE=DATE:20120406
|
||||
DTEND;VALUE=DATE:20120407
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220225Z
|
||||
LAST-MODIFIED:20120117T220232Z
|
||||
DTSTAMP:20120117T220232Z
|
||||
UID:00c93d5e-4c1a-45b0-a4f5-3a60b4ba865b
|
||||
SUMMARY:Easter Sunday
|
||||
DTSTART;VALUE=DATE:20120408
|
||||
DTEND;VALUE=DATE:20120409
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220244Z
|
||||
LAST-MODIFIED:20120117T220251Z
|
||||
DTSTAMP:20120117T220251Z
|
||||
UID:8443f87e-ccc7-4bbc-bdc2-8244f459638f
|
||||
SUMMARY:Vimy Ridge Day
|
||||
DTSTART;VALUE=DATE:20120409
|
||||
DTEND;VALUE=DATE:20120410
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220301Z
|
||||
LAST-MODIFIED:20120117T220307Z
|
||||
DTSTAMP:20120117T220307Z
|
||||
UID:3b2035b3-1b4c-4f08-8a38-5ab3d57ef4bb
|
||||
SUMMARY:Easter Monday
|
||||
DTSTART;VALUE=DATE:20120409
|
||||
DTEND;VALUE=DATE:20120410
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220407Z
|
||||
LAST-MODIFIED:20120117T220411Z
|
||||
DTSTAMP:20120117T220411Z
|
||||
UID:dc725c0c-587a-4f7d-997f-521478528973
|
||||
SUMMARY:Canada Day
|
||||
DTSTART;VALUE=DATE:20120701
|
||||
DTEND;VALUE=DATE:20120702
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220615Z
|
||||
LAST-MODIFIED:20120117T220622Z
|
||||
DTSTAMP:20120117T220622Z
|
||||
UID:5663c847-3a29-492b-aeab-1d009852ad67
|
||||
SUMMARY:Halloween
|
||||
DTSTART;VALUE=DATE:20121031
|
||||
DTEND;VALUE=DATE:20121101
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220859Z
|
||||
LAST-MODIFIED:20120117T220905Z
|
||||
DTSTAMP:20120117T220905Z
|
||||
UID:ab6e8de1-e4cd-46c2-a031-5e030d7d56d2
|
||||
SUMMARY:Christmas Eve
|
||||
DTSTART;VALUE=DATE:20121224
|
||||
DTEND;VALUE=DATE:20121225
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220911Z
|
||||
LAST-MODIFIED:20120117T220917Z
|
||||
DTSTAMP:20120117T220917Z
|
||||
UID:6a7de4c3-bb70-477c-91b8-5d780c19d4ca
|
||||
SUMMARY:Christmas
|
||||
DTSTART;VALUE=DATE:20121225
|
||||
DTEND;VALUE=DATE:20121226
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220920Z
|
||||
LAST-MODIFIED:20120117T220943Z
|
||||
DTSTAMP:20120117T220943Z
|
||||
UID:4913c6ab-5332-4094-811a-f6060616fda3
|
||||
SUMMARY:Boxing Day (Most regions)
|
||||
DTSTART;VALUE=DATE:20121226
|
||||
DTEND;VALUE=DATE:20121227
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220956Z
|
||||
LAST-MODIFIED:20120117T221003Z
|
||||
DTSTAMP:20120117T221003Z
|
||||
UID:43bc10df-bd29-4f2b-aa0f-c6cc8cf3839f
|
||||
SUMMARY:New Year's Eve
|
||||
DTSTART;VALUE=DATE:20121231
|
||||
DTEND;VALUE=DATE:20130101
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T221726Z
|
||||
LAST-MODIFIED:20120117T221734Z
|
||||
DTSTAMP:20120117T221734Z
|
||||
UID:a51d1d54-72c6-4fe7-8080-bb78b3ab0c09
|
||||
SUMMARY:New Year's Day
|
||||
DTSTART;VALUE=DATE:20120101
|
||||
DTEND;VALUE=DATE:20120102
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220055Z
|
||||
LAST-MODIFIED:20120117T221850Z
|
||||
DTSTAMP:20120117T221850Z
|
||||
UID:31cc39a6-9b41-4a5f-9fd2-f5c43ad686fb
|
||||
SUMMARY:Family Day (AB\, ON\, SK)
|
||||
DTSTART;VALUE=DATE:20120220
|
||||
DTEND;VALUE=DATE:20120221
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220125Z
|
||||
LAST-MODIFIED:20120117T221906Z
|
||||
DTSTAMP:20120117T221906Z
|
||||
UID:4370e2c8-0863-456c-b1d0-e64ec8a06ef1
|
||||
SUMMARY:Commonwealth Day
|
||||
DTSTART;VALUE=DATE:20120312
|
||||
DTEND;VALUE=DATE:20120313
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220321Z
|
||||
LAST-MODIFIED:20120117T221951Z
|
||||
DTSTAMP:20120117T221951Z
|
||||
UID:722dc2f8-c0c8-457b-902c-30e94aee23bb
|
||||
SUMMARY:Victoria Day (Most regions)
|
||||
DTSTART;VALUE=DATE:20120521
|
||||
DTEND;VALUE=DATE:20120522
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220346Z
|
||||
LAST-MODIFIED:20120117T222004Z
|
||||
DTSTAMP:20120117T222004Z
|
||||
UID:f782fb4f-7d96-425c-ae58-839d0f8a9283
|
||||
SUMMARY:National Aboriginal Day
|
||||
DTSTART;VALUE=DATE:20120621
|
||||
DTEND;VALUE=DATE:20120622
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220419Z
|
||||
LAST-MODIFIED:20120117T222100Z
|
||||
DTSTAMP:20120117T222100Z
|
||||
UID:e9a8bda0-2fa1-4cdf-94e1-5eb5467869ff
|
||||
SUMMARY:Canada Day - statutory holiday
|
||||
DTSTART;VALUE=DATE:20120702
|
||||
DTEND;VALUE=DATE:20120703
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220450Z
|
||||
LAST-MODIFIED:20120117T222123Z
|
||||
DTSTAMP:20120117T222123Z
|
||||
UID:074e1958-329b-45b8-b918-3d6807c9deb4
|
||||
SUMMARY:Civic/Provincial Day (Many regions)
|
||||
DTSTART;VALUE=DATE:20120806
|
||||
DTEND;VALUE=DATE:20120807
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220527Z
|
||||
LAST-MODIFIED:20120117T222135Z
|
||||
DTSTAMP:20120117T222135Z
|
||||
UID:e2bc628c-79da-4f09-bfbb-b1d1ea9ca79f
|
||||
SUMMARY:Labour Day (All)
|
||||
DTSTART;VALUE=DATE:20120903
|
||||
DTEND;VALUE=DATE:20120904
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220553Z
|
||||
LAST-MODIFIED:20120117T222145Z
|
||||
DTSTAMP:20120117T222145Z
|
||||
UID:ed33f08c-fcb1-44ee-9173-1bd7051093fb
|
||||
SUMMARY:Thanksgiving Day (All)
|
||||
DTSTART;VALUE=DATE:20121008
|
||||
DTEND;VALUE=DATE:20121009
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220635Z
|
||||
LAST-MODIFIED:20120117T222159Z
|
||||
DTSTAMP:20120117T222159Z
|
||||
UID:27bff647-69a4-4be8-9647-6dd1ad3b4d60
|
||||
SUMMARY:Remembrance Day (Most regions)
|
||||
DTSTART;VALUE=DATE:20121111
|
||||
DTEND;VALUE=DATE:20121112
|
||||
X-MOZ-GENERATION:2
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220727Z
|
||||
LAST-MODIFIED:20120117T222205Z
|
||||
DTSTAMP:20120117T222205Z
|
||||
UID:487d87a7-618f-4f07-bba2-9f472be8c836
|
||||
SUMMARY:Remembrance Day observed (Many regions)
|
||||
DTSTART;VALUE=DATE:20121112
|
||||
DTEND;VALUE=DATE:20121113
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20120117T220816Z
|
||||
LAST-MODIFIED:20120117T222220Z
|
||||
DTSTAMP:20120117T222220Z
|
||||
UID:696de927-4e80-4d07-a283-550f51ec324e
|
||||
SUMMARY:Anniversary of the Statute of Westminster
|
||||
DTSTART;VALUE=DATE:20121211
|
||||
DTEND;VALUE=DATE:20121212
|
||||
X-MOZ-GENERATION:1
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
@@ -1,3 +0,0 @@
|
||||
FROM httpd:2.4
|
||||
|
||||
ADD httpd.conf /usr/local/apache2/conf/httpd.conf
|
||||
@@ -1,772 +0,0 @@
|
||||
#
|
||||
# This is the main Apache HTTP server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
|
||||
# In particular, see
|
||||
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
|
||||
# for a discussion of each configuration directive.
|
||||
#
|
||||
# Do NOT simply read the instructions in here without understanding
|
||||
# what they do. They're here only as hints or reminders. If you are unsure
|
||||
# consult the online docs. You have been warned.
|
||||
#
|
||||
# Configuration and logfile names: If the filenames you specify for many
|
||||
# of the server's control files begin with "/" (or "drive:/" for Win32), the
|
||||
# server will use that explicit path. If the filenames do *not* begin
|
||||
# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
|
||||
# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
|
||||
# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
|
||||
# will be interpreted as '/logs/access_log'.
|
||||
|
||||
#
|
||||
# ServerRoot: The top of the directory tree under which the server's
|
||||
# configuration, error, and log files are kept.
|
||||
#
|
||||
# Do not add a slash at the end of the directory path. If you point
|
||||
# ServerRoot at a non-local disk, be sure to specify a local disk on the
|
||||
# Mutex directive, if file-based mutexes are used. If you wish to share the
|
||||
# same ServerRoot for multiple httpd daemons, you will need to change at
|
||||
# least PidFile.
|
||||
#
|
||||
ServerRoot "/usr/local/apache2"
|
||||
|
||||
#
|
||||
# Mutex: Allows you to set the mutex mechanism and mutex file directory
|
||||
# for individual mutexes, or change the global defaults
|
||||
#
|
||||
# Uncomment and change the directory if mutexes are file-based and the default
|
||||
# mutex file directory is not on a local disk or is not appropriate for some
|
||||
# other reason.
|
||||
#
|
||||
# Mutex default:logs
|
||||
|
||||
#
|
||||
# Listen: Allows you to bind Apache to specific IP addresses and/or
|
||||
# ports, instead of the default. See also the <VirtualHost>
|
||||
# directive.
|
||||
#
|
||||
# Change this to Listen on specific IP addresses as shown below to
|
||||
# prevent Apache from glomming onto all bound IP addresses.
|
||||
#
|
||||
#Listen 12.34.56.78:80
|
||||
Listen 80
|
||||
Listen 81
|
||||
Listen 443
|
||||
|
||||
#
|
||||
# Dynamic Shared Object (DSO) Support
|
||||
#
|
||||
# To be able to use the functionality of a module which was built as a DSO you
|
||||
# have to place corresponding `LoadModule' lines at this location so the
|
||||
# directives contained in it are actually available _before_ they are used.
|
||||
# Statically compiled modules (those listed by `httpd -l') do not need
|
||||
# to be loaded here.
|
||||
#
|
||||
# Example:
|
||||
# LoadModule foo_module modules/mod_foo.so
|
||||
#
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
|
||||
#LoadModule authn_anon_module modules/mod_authn_anon.so
|
||||
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
|
||||
#LoadModule authn_socache_module modules/mod_authn_socache.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
|
||||
#LoadModule authz_owner_module modules/mod_authz_owner.so
|
||||
#LoadModule authz_dbd_module modules/mod_authz_dbd.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
|
||||
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
#LoadModule auth_form_module modules/mod_auth_form.so
|
||||
#LoadModule auth_digest_module modules/mod_auth_digest.so
|
||||
#LoadModule allowmethods_module modules/mod_allowmethods.so
|
||||
#LoadModule isapi_module modules/mod_isapi.so
|
||||
#LoadModule file_cache_module modules/mod_file_cache.so
|
||||
#LoadModule cache_module modules/mod_cache.so
|
||||
#LoadModule cache_disk_module modules/mod_cache_disk.so
|
||||
#LoadModule cache_socache_module modules/mod_cache_socache.so
|
||||
#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
|
||||
#LoadModule socache_dbm_module modules/mod_socache_dbm.so
|
||||
#LoadModule socache_memcache_module modules/mod_socache_memcache.so
|
||||
#LoadModule socache_redis_module modules/mod_socache_redis.so
|
||||
#LoadModule watchdog_module modules/mod_watchdog.so
|
||||
#LoadModule macro_module modules/mod_macro.so
|
||||
#LoadModule dbd_module modules/mod_dbd.so
|
||||
#LoadModule bucketeer_module modules/mod_bucketeer.so
|
||||
#LoadModule dumpio_module modules/mod_dumpio.so
|
||||
#LoadModule echo_module modules/mod_echo.so
|
||||
#LoadModule example_hooks_module modules/mod_example_hooks.so
|
||||
#LoadModule case_filter_module modules/mod_case_filter.so
|
||||
#LoadModule case_filter_in_module modules/mod_case_filter_in.so
|
||||
#LoadModule example_ipc_module modules/mod_example_ipc.so
|
||||
#LoadModule buffer_module modules/mod_buffer.so
|
||||
#LoadModule data_module modules/mod_data.so
|
||||
#LoadModule ratelimit_module modules/mod_ratelimit.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
#LoadModule ext_filter_module modules/mod_ext_filter.so
|
||||
#LoadModule request_module modules/mod_request.so
|
||||
#LoadModule include_module modules/mod_include.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
#LoadModule reflector_module modules/mod_reflector.so
|
||||
#LoadModule substitute_module modules/mod_substitute.so
|
||||
#LoadModule sed_module modules/mod_sed.so
|
||||
#LoadModule charset_lite_module modules/mod_charset_lite.so
|
||||
#LoadModule deflate_module modules/mod_deflate.so
|
||||
#LoadModule xml2enc_module modules/mod_xml2enc.so
|
||||
#LoadModule proxy_html_module modules/mod_proxy_html.so
|
||||
#LoadModule brotli_module modules/mod_brotli.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
#LoadModule ldap_module modules/mod_ldap.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
#LoadModule log_debug_module modules/mod_log_debug.so
|
||||
#LoadModule log_forensic_module modules/mod_log_forensic.so
|
||||
#LoadModule logio_module modules/mod_logio.so
|
||||
#LoadModule lua_module modules/mod_lua.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
#LoadModule mime_magic_module modules/mod_mime_magic.so
|
||||
#LoadModule cern_meta_module modules/mod_cern_meta.so
|
||||
#LoadModule expires_module modules/mod_expires.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
#LoadModule ident_module modules/mod_ident.so
|
||||
#LoadModule usertrack_module modules/mod_usertrack.so
|
||||
#LoadModule unique_id_module modules/mod_unique_id.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
#LoadModule remoteip_module modules/mod_remoteip.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
||||
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
|
||||
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
|
||||
#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
|
||||
#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
|
||||
#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
|
||||
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
|
||||
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
||||
#LoadModule proxy_express_module modules/mod_proxy_express.so
|
||||
#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
|
||||
#LoadModule session_module modules/mod_session.so
|
||||
#LoadModule session_cookie_module modules/mod_session_cookie.so
|
||||
#LoadModule session_crypto_module modules/mod_session_crypto.so
|
||||
#LoadModule session_dbd_module modules/mod_session_dbd.so
|
||||
#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
|
||||
#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so
|
||||
#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so
|
||||
#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so
|
||||
#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so
|
||||
#LoadModule dialup_module modules/mod_dialup.so
|
||||
#LoadModule http2_module modules/mod_http2.so
|
||||
#LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
#LoadModule md_module modules/mod_md.so
|
||||
#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
|
||||
#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
|
||||
#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
|
||||
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
#LoadModule heartbeat_module modules/mod_heartbeat.so
|
||||
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
|
||||
#LoadModule dav_module modules/mod_dav.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
#LoadModule asis_module modules/mod_asis.so
|
||||
#LoadModule info_module modules/mod_info.so
|
||||
#LoadModule suexec_module modules/mod_suexec.so
|
||||
<IfModule !mpm_prefork_module>
|
||||
#LoadModule cgid_module modules/mod_cgid.so
|
||||
</IfModule>
|
||||
<IfModule mpm_prefork_module>
|
||||
#LoadModule cgi_module modules/mod_cgi.so
|
||||
</IfModule>
|
||||
#LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||
#LoadModule dav_lock_module modules/mod_dav_lock.so
|
||||
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
|
||||
#LoadModule negotiation_module modules/mod_negotiation.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
#LoadModule imagemap_module modules/mod_imagemap.so
|
||||
#LoadModule actions_module modules/mod_actions.so
|
||||
#LoadModule speling_module modules/mod_speling.so
|
||||
#LoadModule userdir_module modules/mod_userdir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
|
||||
<IfModule unixd_module>
|
||||
#
|
||||
# If you wish httpd to run as a different user or group, you must run
|
||||
# httpd as root initially and it will switch.
|
||||
#
|
||||
# User/Group: The name (or #number) of the user/group to run httpd as.
|
||||
# It is usually good practice to create a dedicated user and group for
|
||||
# running httpd, as with most system services.
|
||||
#
|
||||
User www-data
|
||||
Group www-data
|
||||
|
||||
</IfModule>
|
||||
|
||||
# 'Main' server configuration
|
||||
#
|
||||
# The directives in this section set up the values used by the 'main'
|
||||
# server, which responds to any requests that aren't handled by a
|
||||
# <VirtualHost> definition. These values also provide defaults for
|
||||
# any <VirtualHost> containers you may define later in the file.
|
||||
#
|
||||
# All of these directives may appear inside <VirtualHost> containers,
|
||||
# in which case these default settings will be overridden for the
|
||||
# virtual host being defined.
|
||||
#
|
||||
|
||||
#
|
||||
# ServerAdmin: Your address, where problems with the server should be
|
||||
# e-mailed. This address appears on some server-generated pages, such
|
||||
# as error documents. e.g. admin@your-domain.com
|
||||
#
|
||||
ServerAdmin you@example.com
|
||||
|
||||
#
|
||||
# ServerName gives the name and port that the server uses to identify itself.
|
||||
# This can often be determined automatically, but we recommend you specify
|
||||
# it explicitly to prevent problems during startup.
|
||||
#
|
||||
# If your host doesn't have a registered DNS name, enter its IP address here.
|
||||
#
|
||||
#ServerName www.example.com:80
|
||||
|
||||
#
|
||||
# Deny access to the entirety of your server's filesystem. You must
|
||||
# explicitly permit access to web content directories in other
|
||||
# <Directory> blocks below.
|
||||
#
|
||||
<Directory />
|
||||
AllowOverride none
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
#
|
||||
# Note that from this point forward you must specifically allow
|
||||
# particular features to be enabled - so if something's not working as
|
||||
# you might expect, make sure that you have specifically enabled it
|
||||
# below.
|
||||
#
|
||||
|
||||
#
|
||||
# DocumentRoot: The directory out of which you will serve your
|
||||
# documents. By default, all requests are taken from this directory, but
|
||||
# symbolic links and aliases may be used to point to other locations.
|
||||
#
|
||||
DocumentRoot "/usr/local/apache2/htdocs"
|
||||
<Directory "/usr/local/apache2/htdocs">
|
||||
#
|
||||
# Possible values for the Options directive are "None", "All",
|
||||
# or any combination of:
|
||||
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
|
||||
#
|
||||
# Note that "MultiViews" must be named *explicitly* --- "Options All"
|
||||
# doesn't give it to you.
|
||||
#
|
||||
# The Options directive is both complicated and important. Please see
|
||||
# http://httpd.apache.org/docs/2.4/mod/core.html#options
|
||||
# for more information.
|
||||
#
|
||||
Options Indexes FollowSymLinks
|
||||
|
||||
#
|
||||
# AllowOverride controls what directives may be placed in .htaccess files.
|
||||
# It can be "All", "None", or any combination of the keywords:
|
||||
# AllowOverride FileInfo AuthConfig Limit
|
||||
#
|
||||
AllowOverride None
|
||||
|
||||
#
|
||||
# Controls who can get stuff from this server.
|
||||
#
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
#
|
||||
# DirectoryIndex: sets the file that Apache will serve if a directory
|
||||
# is requested.
|
||||
#
|
||||
<IfModule dir_module>
|
||||
DirectoryIndex index.html
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The following lines prevent .htaccess and .htpasswd files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<Files ".ht*">
|
||||
Require all denied
|
||||
</Files>
|
||||
|
||||
#
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog /proc/self/fd/2
|
||||
|
||||
#
|
||||
# LogLevel: Control the number of messages logged to the error_log.
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
<IfModule log_config_module>
|
||||
#
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive (see below).
|
||||
#
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
||||
|
||||
<IfModule logio_module>
|
||||
# You need to enable mod_logio.c to use %I and %O
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The location and format of the access logfile (Common Logfile Format).
|
||||
# If you do not define any access logfiles within a <VirtualHost>
|
||||
# container, they will be logged here. Contrariwise, if you *do*
|
||||
# define per-<VirtualHost> access logfiles, transactions will be
|
||||
# logged therein and *not* in this file.
|
||||
#
|
||||
CustomLog /proc/self/fd/1 common
|
||||
|
||||
#
|
||||
# If you prefer a logfile with access, agent, and referer information
|
||||
# (Combined Logfile Format) you can use the following directive.
|
||||
#
|
||||
#CustomLog "logs/access_log" combined
|
||||
</IfModule>
|
||||
|
||||
<IfModule alias_module>
|
||||
#
|
||||
# Redirect: Allows you to tell clients about documents that used to
|
||||
# exist in your server's namespace, but do not anymore. The client
|
||||
# will make a new request for the document at its new location.
|
||||
# Example:
|
||||
# Redirect permanent /foo http://www.example.com/bar
|
||||
|
||||
#
|
||||
# Alias: Maps web paths into filesystem paths and is used to
|
||||
# access content that does not live under the DocumentRoot.
|
||||
# Example:
|
||||
# Alias /webpath /full/filesystem/path
|
||||
#
|
||||
# If you include a trailing / on /webpath then the server will
|
||||
# require it to be present in the URL. You will also likely
|
||||
# need to provide a <Directory> section to allow access to
|
||||
# the filesystem path.
|
||||
|
||||
#
|
||||
# ScriptAlias: This controls which directories contain server scripts.
|
||||
# ScriptAliases are essentially the same as Aliases, except that
|
||||
# documents in the target directory are treated as applications and
|
||||
# run by the server when requested rather than as documents sent to the
|
||||
# client. The same rules about trailing "/" apply to ScriptAlias
|
||||
# directives as to Alias.
|
||||
#
|
||||
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
|
||||
|
||||
</IfModule>
|
||||
|
||||
<IfModule cgid_module>
|
||||
#
|
||||
# ScriptSock: On threaded servers, designate the path to the UNIX
|
||||
# socket used to communicate with the CGI daemon of mod_cgid.
|
||||
#
|
||||
#Scriptsock cgisock
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased
|
||||
# CGI directory exists, if you have that configured.
|
||||
#
|
||||
<Directory "/usr/local/apache2/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<IfModule headers_module>
|
||||
#
|
||||
# Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
|
||||
# backend servers which have lingering "httpoxy" defects.
|
||||
# 'Proxy' request header is undefined by the IETF, not listed by IANA
|
||||
#
|
||||
RequestHeader unset Proxy early
|
||||
</IfModule>
|
||||
|
||||
<IfModule mime_module>
|
||||
#
|
||||
# TypesConfig points to the file containing the list of mappings from
|
||||
# filename extension to MIME-type.
|
||||
#
|
||||
TypesConfig conf/mime.types
|
||||
|
||||
#
|
||||
# AddType allows you to add to or override the MIME configuration
|
||||
# file specified in TypesConfig for specific file types.
|
||||
#
|
||||
#AddType application/x-gzip .tgz
|
||||
#
|
||||
# AddEncoding allows you to have certain browsers uncompress
|
||||
# information on the fly. Note: Not all browsers support this.
|
||||
#
|
||||
#AddEncoding x-compress .Z
|
||||
#AddEncoding x-gzip .gz .tgz
|
||||
#
|
||||
# If the AddEncoding directives above are commented-out, then you
|
||||
# probably should define those extensions to indicate media types:
|
||||
#
|
||||
AddType application/x-compress .Z
|
||||
AddType application/x-gzip .gz .tgz
|
||||
|
||||
#
|
||||
# AddHandler allows you to map certain file extensions to "handlers":
|
||||
# actions unrelated to filetype. These can be either built into the server
|
||||
# or added with the Action directive (see below)
|
||||
#
|
||||
# To use CGI scripts outside of ScriptAliased directories:
|
||||
# (You will also need to add "ExecCGI" to the "Options" directive.)
|
||||
#
|
||||
#AddHandler cgi-script .cgi
|
||||
|
||||
# For type maps (negotiated resources):
|
||||
#AddHandler type-map var
|
||||
|
||||
#
|
||||
# Filters allow you to process content before it is sent to the client.
|
||||
#
|
||||
# To parse .shtml files for server-side includes (SSI):
|
||||
# (You will also need to add "Includes" to the "Options" directive.)
|
||||
#
|
||||
#AddType text/html .shtml
|
||||
#AddOutputFilter INCLUDES .shtml
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The mod_mime_magic module allows the server to use various hints from the
|
||||
# contents of the file itself to determine its type. The MIMEMagicFile
|
||||
# directive tells the module where the hint definitions are located.
|
||||
#
|
||||
#MIMEMagicFile conf/magic
|
||||
|
||||
#
|
||||
# Customizable error responses come in three flavors:
|
||||
# 1) plain text 2) local redirects 3) external redirects
|
||||
#
|
||||
# Some examples:
|
||||
#ErrorDocument 500 "The server made a boo boo."
|
||||
#ErrorDocument 404 /missing.html
|
||||
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
|
||||
#ErrorDocument 402 http://www.example.com/subscription_info.html
|
||||
#
|
||||
|
||||
#
|
||||
# MaxRanges: Maximum number of Ranges in a request before
|
||||
# returning the entire resource, or one of the special
|
||||
# values 'default', 'none' or 'unlimited'.
|
||||
# Default setting is to accept 200 Ranges.
|
||||
#MaxRanges unlimited
|
||||
|
||||
#
|
||||
# EnableMMAP and EnableSendfile: On systems that support it,
|
||||
# memory-mapping or the sendfile syscall may be used to deliver
|
||||
# files. This usually improves server performance, but must
|
||||
# be turned off when serving from networked-mounted
|
||||
# filesystems or if support for these functions is otherwise
|
||||
# broken on your system.
|
||||
# Defaults: EnableMMAP On, EnableSendfile Off
|
||||
#
|
||||
#EnableMMAP off
|
||||
#EnableSendfile on
|
||||
|
||||
# Supplemental configuration
|
||||
#
|
||||
# The configuration files in the conf/extra/ directory can be
|
||||
# included to add extra features or to modify the default configuration of
|
||||
# the server, or you may simply copy their contents here and change as
|
||||
# necessary.
|
||||
|
||||
# Server-pool management (MPM specific)
|
||||
#Include conf/extra/httpd-mpm.conf
|
||||
|
||||
# Multi-language error messages
|
||||
#Include conf/extra/httpd-multilang-errordoc.conf
|
||||
|
||||
# Fancy directory listings
|
||||
#Include conf/extra/httpd-autoindex.conf
|
||||
|
||||
# Language settings
|
||||
#Include conf/extra/httpd-languages.conf
|
||||
|
||||
# User home directories
|
||||
#Include conf/extra/httpd-userdir.conf
|
||||
|
||||
# Real-time info on requests and configuration
|
||||
#Include conf/extra/httpd-info.conf
|
||||
|
||||
# Virtual hosts
|
||||
#Include conf/extra/httpd-vhosts.conf
|
||||
|
||||
# Local access to the Apache HTTP Server Manual
|
||||
#Include conf/extra/httpd-manual.conf
|
||||
|
||||
# Distributed authoring and versioning (WebDAV)
|
||||
#Include conf/extra/httpd-dav.conf
|
||||
|
||||
# Various default settings
|
||||
#Include conf/extra/httpd-default.conf
|
||||
|
||||
# Configure mod_proxy_html to understand HTML4/XHTML1
|
||||
<IfModule proxy_html_module>
|
||||
Include conf/extra/proxy-html.conf
|
||||
</IfModule>
|
||||
|
||||
# Secure (SSL/TLS) connections
|
||||
#Include conf/extra/httpd-ssl.conf
|
||||
#
|
||||
# Note: The following must must be present to support
|
||||
# starting without SSL on platforms with no /dev/random equivalent
|
||||
# but a statically compiled-in mod_ssl.
|
||||
#
|
||||
<IfModule ssl_module>
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed connect builtin
|
||||
</IfModule>
|
||||
|
||||
|
||||
###########################
|
||||
#
|
||||
# SOGo HTTP
|
||||
#
|
||||
###########################
|
||||
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin support@sogo.nu
|
||||
ServerName dev.sogo
|
||||
|
||||
Alias /SOGo.woa/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
Alias /SOGo/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
|
||||
<Directory /usr/lib/GNUstep/SOGo/>
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
|
||||
# Explicitly allow caching of static content to avoid browser specific behavior.
|
||||
# A resource's URL MUST change in order to have the client load the new version.
|
||||
<IfModule expires_module>
|
||||
ExpiresActive On
|
||||
ExpiresDefault "access plus 1 year"
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
CustomLog /tmp/sogo.log combined
|
||||
|
||||
ProxyRequests Off
|
||||
SetEnv proxy-nokeepalive 1
|
||||
ProxyPreserveHost On
|
||||
ProxyPass /SOGo http://sogo:50000/SOGo retry=0
|
||||
ProxyPass /Microsoft-Server-ActiveSync http://sogo:50000/SOGo/Microsoft-Server-ActiveSync retry=0 connectiontimeout=5 timeout=3600
|
||||
ProxyPass /keycloak http://keycloak:8080/keycloak retry=0
|
||||
ProxyPassReverse /keycloak http://keycloak:8080/keycloak
|
||||
|
||||
<Proxy http://sogo:50000/SOGo>
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "80"
|
||||
RequestHeader set "x-webobjects-server-name" "127.0.0.1"
|
||||
RequestHeader set "x-webobjects-server-url" "http://127.0.0.1"
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
|
||||
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Proxy>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteRule ^/SOGo/(.*)$ /SOGo/$1 [env=REMOTE_HOST:%{REMOTE_ADDR},PT]
|
||||
|
||||
# For Apple autoconfiguration
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
|
||||
</IfModule>
|
||||
|
||||
<Directory /src/SOGo/Tests/results>
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
Alias /tests /src/SOGo/Tests/results
|
||||
</VirtualHost>
|
||||
|
||||
###########################
|
||||
#
|
||||
# SOGo HTTP (for tests)
|
||||
#
|
||||
###########################
|
||||
|
||||
<VirtualHost *:81>
|
||||
ServerAdmin support@sogo.nu
|
||||
ServerName dev.sogo
|
||||
|
||||
Alias /SOGo.woa/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
Alias /SOGo/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
|
||||
<Directory /usr/lib/GNUstep/SOGo/>
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
|
||||
# Explicitly allow caching of static content to avoid browser specific behavior.
|
||||
# A resource's URL MUST change in order to have the client load the new version.
|
||||
<IfModule expires_module>
|
||||
ExpiresActive On
|
||||
ExpiresDefault "access plus 1 year"
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
CustomLog /tmp/sogo.log combined
|
||||
|
||||
ProxyRequests Off
|
||||
SetEnv proxy-nokeepalive 1
|
||||
ProxyPreserveHost On
|
||||
ProxyPass /SOGo http://sogo:50000/SOGo retry=0
|
||||
ProxyPass /Microsoft-Server-ActiveSync http://sogo:50000/SOGo/Microsoft-Server-ActiveSync retry=0 connectiontimeout=5 timeout=3600
|
||||
|
||||
<Proxy http://sogo:50000/SOGo>
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "81"
|
||||
RequestHeader set "x-webobjects-server-name" "httpd"
|
||||
RequestHeader set "x-webobjects-server-url" "http://httpd"
|
||||
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
RequestHeader set "x-webobjects-remote-host" "httpd"
|
||||
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Proxy>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteRule ^/SOGo/(.*)$ /SOGo/$1 [env=REMOTE_HOST:%{REMOTE_ADDR},PT]
|
||||
|
||||
# For Apple autoconfiguration
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
|
||||
</IfModule>
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
###########################
|
||||
#
|
||||
# SOGo HTTPS
|
||||
#
|
||||
###########################
|
||||
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerAdmin support@sogo.nu
|
||||
ServerName dev.sogo
|
||||
|
||||
Alias /SOGo.woa/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
Alias /SOGo/WebServerResources/ /usr/local/lib/GNUstep/SOGo/WebServerResources/
|
||||
|
||||
SSLEngine on
|
||||
SSLCertificateFile /ssl/apache-selfsigned.crt
|
||||
SSLCertificateKeyFile /ssl/apache-selfsigned.key
|
||||
|
||||
<Directory /usr/lib/GNUstep/SOGo/>
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
|
||||
# Explicitly allow caching of static content to avoid browser specific behavior.
|
||||
# A resource's URL MUST change in order to have the client load the new version.
|
||||
<IfModule expires_module>
|
||||
ExpiresActive On
|
||||
ExpiresDefault "access plus 1 year"
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
CustomLog /tmp/sogo.log combined
|
||||
|
||||
ProxyRequests Off
|
||||
SetEnv proxy-nokeepalive 1
|
||||
ProxyPreserveHost On
|
||||
ProxyPass /SOGo http://sogo:50000/SOGo retry=0
|
||||
ProxyPass /Microsoft-Server-ActiveSync http://sogo:50000/SOGo/Microsoft-Server-ActiveSync retry=0 connectiontimeout=5 timeout=3600
|
||||
ProxyPass /keycloak http://keycloak:8080/keycloak retry=0
|
||||
ProxyPassReverse /keycloak http://keycloak:8080/keycloak
|
||||
|
||||
<Proxy http://sogo:50000/SOGo>
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "443"
|
||||
RequestHeader set "x-webobjects-server-name" "127.0.0.1"
|
||||
RequestHeader set "x-webobjects-server-url" "https://127.0.0.1"
|
||||
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
|
||||
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Proxy>
|
||||
|
||||
|
||||
RewriteEngine On
|
||||
RewriteRule ^/SOGo/(.*)$ /SOGo/$1 [env=REMOTE_HOST:%{REMOTE_ADDR},PT]
|
||||
|
||||
# For Apple autoconfiguration
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
|
||||
</IfModule>
|
||||
|
||||
<Directory /src/SOGo/Tests/results>
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
Alias /tests /src/SOGo/Tests/results
|
||||
</VirtualHost>
|
||||
@@ -1,20 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIUCMtp7zGBSm27mjkmvqMww9BtkBowDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA3MjcyMjM4MTdaFw0zNDA3
|
||||
MjUyMjM4MTdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCtpzPeBvnCJJD36iaTClW1dprzqs9yMqEyLHaczOIm
|
||||
VEsUG6ykWx1XpH4adAfVuVkyKgIuVWK57F4wmDq6mpyycfIbhT2r93fWkW5k10vU
|
||||
c1QG6CPiQs01n0H3BqMXfbkYmJ5Re63cDawRT5aofpc2ClSk7odrL2cF0keb84qB
|
||||
4b6M4D2fGEL9dkwzXeKysMqmcur6jsfAv1ojB4lie+q2UR3VIvU2OP8NQckJJ4le
|
||||
O5i20gR5iX71KykgCy4J2OelU18RH3yY9AZd+m6rWokIqqvS3Izz1hTRC7TQUDql
|
||||
RCWCCyLZolWs9T5K2i23lpswWX+bjtkR1NAqPy+W0WJfAgMBAAGjITAfMB0GA1Ud
|
||||
DgQWBBTUzyYg3BCKqzFWJSu/iTNxknyphjANBgkqhkiG9w0BAQsFAAOCAQEAouJq
|
||||
l6vdg5x/nOBRO+opqIetyc0iux/aJb4QxcMgMgH0c756+EhIFtkx6oxMf7PfNqXF
|
||||
xykkjE5qRMWdtYRsR9unYX/aXJG22iHce9rbK7NgQe0UvqfTZcHCLuvjJA+Iyxnk
|
||||
KPUboPoBqE9ByOhX9NnMBkmhJPe/l4pE0h8hXPEFYvTDfAYYFh6+4JAtEqF+E8ZW
|
||||
UBPZLG+nM48TuPte8iWRHZyn70h2dGQ05Wzlov58ftV1AY5BAo7z3b/ZCEz3gTNe
|
||||
+TcN413F1drctxjSXAd5OuqTEUOutaUwdwAbRQpOXuMDabXGQvTXMIRnHG0QLmQo
|
||||
YzVEGaUAWP4MeXrvIQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,16 +0,0 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
|
||||
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAK2nM94G+cIkkPfqJpMKVbV2mvOqz3IyoTIsdpzM
|
||||
4iZUSxQbrKRbHVekfhp0B9W5WTIqAi5VYrnsXjCYOrqanLJx8huFPav3d9aRbmTX
|
||||
S9RzVAboI+JCzTWfQfcGoxd9uRiYnlF7rdwNrBFPlqh+lzYKVKTuh2svZwXSR5vz
|
||||
ioHhvozgPZ8YQv12TDNd4rKwyqZy6vqOx8C/WiMHiWJ76rZRHdUi9TY4/w1ByQkn
|
||||
iV47mLbSBHmJfvUrKSALLgnY56VTXxEffJj0Bl36bqtaiQiqq9LcjPPWFNELtNBQ
|
||||
OqVEJYILItmiVaz1PkraLbeWmzBZf5uO2RHU0Co/L5bRYl8CAwEAAaAAMA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQBgCABl1ViXYbRIMtZR4UA2Cd0jY5kqMq0CePWHDYOI+eUP
|
||||
qcnx+sVNZN5ixDdm3Dv6g7dwu3g8FZ3oC/jS/JhTJbbVubPq21T3nv0ZIOL3rmMp
|
||||
hJsWBBanVgLi3MD+UsF/2IrJYf7mOR2OEVmb4dglUJNgkcbuaTA4nF5nFS/gVZxg
|
||||
id6wvGygNuoGXhWVOC1amr+xYqt6Wv/U2vA8fQ9LWL7L7/eU2ol2VurC8bEAQYRR
|
||||
7O8WOk9j2njDRzE8HHKg7iSSDleMiYtAcs2HIljlTAB7mQolkYpcfyIOE1wFWG14
|
||||
IhS/p2SxHfvUKvJIgauG7DkFeURRtnqEioB2JwyE
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtpzPeBvnCJJD3
|
||||
6iaTClW1dprzqs9yMqEyLHaczOImVEsUG6ykWx1XpH4adAfVuVkyKgIuVWK57F4w
|
||||
mDq6mpyycfIbhT2r93fWkW5k10vUc1QG6CPiQs01n0H3BqMXfbkYmJ5Re63cDawR
|
||||
T5aofpc2ClSk7odrL2cF0keb84qB4b6M4D2fGEL9dkwzXeKysMqmcur6jsfAv1oj
|
||||
B4lie+q2UR3VIvU2OP8NQckJJ4leO5i20gR5iX71KykgCy4J2OelU18RH3yY9AZd
|
||||
+m6rWokIqqvS3Izz1hTRC7TQUDqlRCWCCyLZolWs9T5K2i23lpswWX+bjtkR1NAq
|
||||
Py+W0WJfAgMBAAECggEAETSSfFp56d/FnUqjLR5xBNxjgzur93HyFrk2Z1gaxWwZ
|
||||
+ZFkYZnFe9GId7EstY2lEMX+FqkkcazBsv7iPWrkQP9D2wYwk2v0K7DtHICturb9
|
||||
NFH70YcyMzCRpfAPvgbEOB5RprEiYL3aC+e0KFhNPcV4QtR/W6yuqxz9NgPDTWru
|
||||
g061RKNlqkeNUp5cnOWhj2Z98SfyZEmN8eIYNW0/neGHiYzXgrpWNvlu5Y1yuZxF
|
||||
ztapr4Oigl6CK7uJ0fOMRsGDdpjfAmOaXGJn2Y848VjUDvlj4HuyW2InPvDwd5t2
|
||||
Do/1zqasMMPl+xa7729Sr5oWYu4IaG/sTTLGQNC2gQKBgQDoeXAQDtwxche3Bddw
|
||||
WEn6ZtpbgDyeoDroZ4P9Fzyq5Rc3HJxv4WFILlYR16buJlPn7QARUD8r2/n+oTiA
|
||||
CN75z5YDKoRmKbCflp2OHmSWWCd7lIzpxaOoOwtPYhOWyaR4BEfaGPjowUz0XBfr
|
||||
Zp80APMOhNZKeeLUOR+Skk09VwKBgQC/Oevluv9rvELX2h09BvE63ZwHjdqW0xaz
|
||||
udSGATpssOeu+9k4E0WKqbyzIhYzR0tGYDHqgdAvU5sr++q/ImhIrz4qRgBSBZs1
|
||||
/1DvbarjogoSZK4lKB20vme+b329sv4TE1c+tusFmLQc+beS67MWfCtvoRzT79Lj
|
||||
WVjhUWjWOQKBgQDParIykZ+iukIweRTMVunCcYw3gYYUna+RdfKMmPP3IimBcZSe
|
||||
Of/bMAR5LOjyqN3KG2opCGkkj8NQjbXkfoW7a5xTvNaedGnzKaXvjGyAu6yWlWbY
|
||||
mQ845V1k+YOy0LxenKsjC47h1L39dEGfNVOsSYCTHrA3iOJ6KXFjDAfARwKBgAqK
|
||||
yet/VKd+2HyH5MbBhDkHkJuGAYABISZFX2cH2E23rv4hmkcSIOpVEzcY8PpgutCl
|
||||
avsPrwd853gUSkvBPNiM+LNh6pCbCISAj9izRhGIlF+RN1yLCqA1Qwjnopn7rTAm
|
||||
B9BIS0qisYNLbQhngBcEP2zHCAzTEuA/w7ugPlRZAoGBAK2wW8ByG3DagT2S4BPB
|
||||
kR/199rdPlNDr6x/BUdceYD76+ZvUsE+mJpzyluU4ECJwNlWLQZkw4uAaRWUNGP6
|
||||
wPYQH2LwXLoj9kxckHEdrC9S0uyEs7A8j60SrGGEtylLG7xS9LyGWj3ZwrycmPoA
|
||||
DOKRLBQCahiob4BAfDfQjXDg
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -f apache-selfsigned.key apache-selfsigned.csr apache-selfsigned.crt
|
||||
openssl genpkey -algorithm RSA -out apache-selfsigned.key
|
||||
openssl req -new -key apache-selfsigned.key -out apache-selfsigned.csr
|
||||
openssl x509 -req -days 3650 -in apache-selfsigned.csr -signkey apache-selfsigned.key -out apache-selfsigned.crt
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
# extended LDIF
|
||||
#
|
||||
# LDAPv3
|
||||
# base <dc=example,dc=org> with scope subtree
|
||||
# filter: (objectclass=*)
|
||||
# requesting: ALL
|
||||
#
|
||||
|
||||
# example.org
|
||||
dn: dc=example,dc=org
|
||||
objectClass: dcObject
|
||||
objectClass: organization
|
||||
dc: example
|
||||
o: example
|
||||
|
||||
# users, example.org
|
||||
dn: ou=users,dc=example,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: users
|
||||
|
||||
dn: ou=groups,dc=example,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: uid=sogo,ou=users,dc=example,dc=org
|
||||
uid: sogo
|
||||
cn: Sogo
|
||||
sn: Sogo
|
||||
mail: sogo@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/sogo
|
||||
|
||||
dn: uid=cyrus,ou=users,dc=example,dc=org
|
||||
uid: cyrus
|
||||
cn: cyrus
|
||||
sn: cyrus
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/cyrus
|
||||
|
||||
dn: uid=sogo-tests1,ou=users,dc=example,dc=org
|
||||
uid: sogo-tests1
|
||||
cn: Dude
|
||||
sn: Love
|
||||
givenName: Dude
|
||||
homePhone: +1 (123) 456-7890
|
||||
l: Vladivostok
|
||||
telephoneNumber: +1 (120) 987-6543
|
||||
mail: sogo-tests1@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/sogo-tests1
|
||||
|
||||
dn: uid=sogo-tests2,ou=users,dc=example,dc=org
|
||||
uid: sogo-tests2
|
||||
cn: Hewill
|
||||
sn: Crashit
|
||||
givenName: Hewill
|
||||
homePhone: +1 (123) 456-7890
|
||||
l: Vladivostok
|
||||
telephoneNumber: +1 (120) 987-6543
|
||||
mail: sogo-tests2@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/sogo-tests2
|
||||
|
||||
dn: uid=sogo-tests3,ou=users,dc=example,dc=org
|
||||
uid: sogo-tests3
|
||||
cn: Ithas
|
||||
sn: Exploded
|
||||
givenName: Ithas
|
||||
homePhone: +1 (123) 456-7890
|
||||
l: Vladivostok
|
||||
telephoneNumber: +1 (120) 987-6543
|
||||
mail: sogo-tests3@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/sogo-tests3
|
||||
|
||||
dn: uid=sogo-tests-super,ou=users,dc=example,dc=org
|
||||
uid: sogo-tests-super
|
||||
cn: John Doe
|
||||
sn: Doe
|
||||
givenName: John
|
||||
homePhone: +1 (123) 456-7890
|
||||
l: Vladivostok
|
||||
telephoneNumber: +1 (120) 987-6543
|
||||
mail: sogo-tests-super@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/sogo-tests-super
|
||||
|
||||
dn: uid=res,ou=users,dc=example,dc=org
|
||||
uid: res
|
||||
cn: resource No Overbook
|
||||
sn: source
|
||||
departmentNumber: 1
|
||||
description: location
|
||||
givenName: res
|
||||
mail: res@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/res
|
||||
|
||||
dn: uid=res-nolimit,ou=users,dc=example,dc=org
|
||||
uid: res-nolimit
|
||||
cn: resource Overbook
|
||||
sn: source
|
||||
departmentNumber: 0
|
||||
description: location
|
||||
givenName: res-nolimit
|
||||
mail: res-nolimit@example.org
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
userPassword:: c29nbw==
|
||||
uidNumber: 1000
|
||||
gidNumber: 1000
|
||||
homeDirectory: /home/res-nolimit
|
||||
|
||||
# readers, users, example.org
|
||||
dn: uid=readers,ou=users,dc=example,dc=org
|
||||
objectClass: extensibleObject
|
||||
objectClass: groupOfNames
|
||||
cn: readers
|
||||
mail: readers@example.org
|
||||
member: uid=sogo-tests1,ou=users,dc=example,dc=org
|
||||
member: uid=sogo-tests2,ou=users,dc=example,dc=org
|
||||
member: uid=sogo-tests3,ou=users,dc=example,dc=org
|
||||
|
||||
|
||||
# search result
|
||||
search: 2
|
||||
result: 0 Success
|
||||
|
||||
# numResponses: 14
|
||||
# numEntries: 13
|
||||
@@ -1,8 +0,0 @@
|
||||
# original catatnight/postfix
|
||||
FROM agiledigital/postfix:latest
|
||||
|
||||
ADD main.cf /etc/postfix/main.cf
|
||||
ADD mailname /etc/mailname
|
||||
ADD virtual /etc/postfix/virtual
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cp /etc/postfix/main.cf /etc/postfix/main.cf.bak
|
||||
chown root:root /etc/postfix/virtual
|
||||
chown root:root /etc/postfix/virtual.db
|
||||
postmap /etc/postfix/virtual
|
||||
|
||||
/opt/install.sh
|
||||
# /opt/install.sh make changes /etc/postfix/main.cf, so restore bak file
|
||||
rm -f /etc/postfix/main.cf
|
||||
cp /etc/postfix/main.cf.bak /etc/postfix/main.cf
|
||||
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
@@ -1 +0,0 @@
|
||||
example.org
|
||||
@@ -1,52 +0,0 @@
|
||||
# Debian specific: Specifying a file name will cause the first
|
||||
# line of that file to be used as the name. The Debian default
|
||||
# is /etc/mailname.
|
||||
#myorigin = /etc/mailname
|
||||
|
||||
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
|
||||
biff = no
|
||||
|
||||
# appending .domain is the MUA's job.
|
||||
append_dot_mydomain = no
|
||||
|
||||
# Uncomment the next line to generate "delayed mail" warnings
|
||||
#delay_warning_time = 4h
|
||||
|
||||
readme_directory = no
|
||||
|
||||
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 3.6 on
|
||||
# fresh installs.
|
||||
compatibility_level = 3.6
|
||||
|
||||
# TLS parameters
|
||||
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
smtpd_tls_security_level=may
|
||||
|
||||
smtp_tls_CApath=/etc/ssl/certs
|
||||
smtp_tls_security_level=may
|
||||
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||
|
||||
smtp_sender_dependent_authentication = yes
|
||||
smtp_sasl_auth_enable = yes
|
||||
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
|
||||
|
||||
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
|
||||
myhostname = localhost
|
||||
alias_maps = hash:/etc/aliases
|
||||
alias_database = hash:/etc/aliases
|
||||
mydestination = example.org
|
||||
mydomain = example.org
|
||||
relayhost =
|
||||
mailbox_size_limit = 51200000
|
||||
recipient_delimiter =
|
||||
inet_interfaces = all
|
||||
inet_protocols = all
|
||||
maillog_file = /var/log/mail.log
|
||||
myorigin = /etc/mailname
|
||||
default_transport = error
|
||||
relay_transport = error
|
||||
|
||||
mailbox_transport = lmtp:inet:imapd:24
|
||||
|
||||
local_recipient_maps = hash:/etc/postfix/virtual
|
||||
@@ -1 +0,0 @@
|
||||
@example.org root
|
||||
@@ -1,518 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
TESTS_RET=0
|
||||
SRC_SOPE=$1
|
||||
SRC_SOGO=$2
|
||||
TESTS_FAILED=false
|
||||
TESTS_RESULTS=()
|
||||
JSON_TEST_RESULTS_PATH="/tmp/tests_results.json"
|
||||
|
||||
export TERM=xterm
|
||||
|
||||
# formatting
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
underline=$(tput smul)
|
||||
no_underline=$(tput rmul)
|
||||
red=$(tput setaf 1)
|
||||
green=$(tput setaf 2)
|
||||
yellow=$(tput setaf 3)
|
||||
blue=$(tput setaf 4)
|
||||
magenta=$(tput setaf 5)
|
||||
cyan=$(tput setaf 6)
|
||||
white=$(tput setaf 7)
|
||||
|
||||
title() {
|
||||
echo "${bold}${cyan}$1${normal}"
|
||||
}
|
||||
|
||||
subtitle() {
|
||||
echo "${magenta}$1${normal}"
|
||||
}
|
||||
|
||||
subsubtitle() {
|
||||
echo "${cyan}$1${normal}"
|
||||
}
|
||||
|
||||
texterror() {
|
||||
echo "${bold}${red}$1${normal}"
|
||||
}
|
||||
|
||||
textwarning() {
|
||||
echo "${bold}${yellow}$1${normal}"
|
||||
}
|
||||
|
||||
textsuccess() {
|
||||
echo "${bold}${green}$1${normal}"
|
||||
}
|
||||
|
||||
stepsuccess() {
|
||||
echo -e "$1 ${bold}${green}✔ ${normal}${bold}$2${normal}"
|
||||
}
|
||||
|
||||
steperror() {
|
||||
echo -e "$1 ${bold}${red}𐄂 ${normal}${bold}$2${normal}"
|
||||
}
|
||||
|
||||
in_array() {
|
||||
local SEARCH_ELEMENT
|
||||
SEARCH_ELEMENT="$1"
|
||||
shift
|
||||
local ELEMENT
|
||||
for ELEMENT in "$@"; do
|
||||
if [[ "$ELEMENT" == "$SEARCH_ELEMENT" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
is_in_docker() {
|
||||
if [ -f /.dockerenv ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_latest_github_commit_hash() {
|
||||
REPO="$1"
|
||||
BRANCH="${2:-master}"
|
||||
TOKEN="$3"
|
||||
GITHUB_API_URL="https://api.github.com/repos/$REPO/commits/$BRANCH"
|
||||
LATEST_COMMIT_HASH=$(curl -s -k -H "Authorization: token $TOKEN" $GITHUB_API_URL | grep '"sha"' | head -n 1 | awk '{print $2}' | tr -d '",')
|
||||
|
||||
echo "$LATEST_COMMIT_HASH"
|
||||
}
|
||||
|
||||
build_system_header() {
|
||||
echo "${white} "
|
||||
echo "${white} "
|
||||
echo "${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} "
|
||||
echo "${white} ${bold}${green}BUILD SYSTEM${normal} "
|
||||
echo "${white} "
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
check_exit_code() {
|
||||
local EXIT_CODE=$?
|
||||
if [ $EXIT_CODE -ne 0 ]; then
|
||||
return $EXIT_CODE
|
||||
fi
|
||||
}
|
||||
|
||||
function prep_tests {
|
||||
# install node modules
|
||||
cd "$SRC_SOGO/Tests" && \
|
||||
npm config set loglevel=error && \
|
||||
npm install > /dev/null
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nError installing node modules"
|
||||
error_out
|
||||
fi
|
||||
|
||||
# fixup the tests configuration
|
||||
cd "$SRC_SOGO/Tests/lib" && \
|
||||
cat >config.js <<EOF
|
||||
export default {
|
||||
hostname: "httpd",
|
||||
port: "81",
|
||||
username: "sogo-tests1",
|
||||
password: "sogo",
|
||||
superuser: "sogo-tests-super",
|
||||
superuser_password: "sogo",
|
||||
subscriber_username: "sogo-tests2",
|
||||
subscriber_password: "sogo",
|
||||
attendee1: "sogo-tests2@example.org",
|
||||
attendee1_username: "sogo-tests2",
|
||||
attendee1_password: "sogo",
|
||||
attendee1_delegate: "sogo-tests3@example.org",
|
||||
attendee1_delegate_username: "sogo-tests3",
|
||||
attendee1_delegate_password: "sogo",
|
||||
resource_no_overbook: "res",
|
||||
resource_can_overbook: "res-nolimit",
|
||||
white_listed_attendee: {
|
||||
"sogo-tests1": "John Doe <sogo-tests1@example.org>"
|
||||
},
|
||||
mailserver: "dovecot",
|
||||
testput_nbrdays: 30,
|
||||
sieve_server: "dovecot",
|
||||
sieve_port: 4190,
|
||||
sogo_user: "sogo",
|
||||
sogo_tool_path: "/usr/sbin/sogo-tool",
|
||||
webCalendarURL: "http://httpd/CanadaHolidays.ics",
|
||||
timeout: 600000
|
||||
}
|
||||
EOF
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nError creating config.js"
|
||||
error_out
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
||||
function prep_tests_mysql {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-mysql-ldap.conf /etc/sogo/sogo.conf
|
||||
|
||||
TMP_FILE=$(mktemp)
|
||||
chmod 600 $TMP_FILE
|
||||
cat <<EOF > $TMP_FILE
|
||||
[client]
|
||||
user = sogobuild
|
||||
password = sogo123
|
||||
host = mariadb
|
||||
EOF
|
||||
|
||||
# drop the mysql database and recreate it
|
||||
echo "drop database sogo_integration_tests;" | mysql --defaults-extra-file=$TMP_FILE -h mariadb
|
||||
echo "create database sogo_integration_tests charset=utf8;" | mysql --defaults-extra-file=$TMP_FILE -h mariadb
|
||||
|
||||
rm $TMP_FILE
|
||||
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nError recreating MySQL database"
|
||||
error_out
|
||||
fi
|
||||
}
|
||||
|
||||
function prep_tests_postgresql {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-postgresql-ldap.conf /etc/sogo/sogo.conf
|
||||
|
||||
# drop the postgresql database and recreate it
|
||||
# the env var is unsafe, i know... just easier and non sensitive anyway
|
||||
PGPASSWORD=sogo123 dropdb -U sogobuild -h postgres sogo_integration_tests
|
||||
PGPASSWORD=sogo123 createdb -O sogobuild -U sogobuild -h postgres sogo_integration_tests
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nError recreating postgresql database"
|
||||
error_out
|
||||
fi
|
||||
}
|
||||
|
||||
function prep_tests_mysql_auth {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-mysql.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function prep_tests_postgresql_auth {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-postgresql.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function prep_tests_mysql_combined {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-mysql-ldap-combined.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function prep_tests_mysql_auth_combined {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-mysql-combined.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function prep_tests_postgresql_combined {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-postgresql-ldap-combined.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function prep_tests_postgresql_auth_combined {
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-tests-postgresql-combined.conf /etc/sogo/sogo.conf
|
||||
}
|
||||
|
||||
function error_out {
|
||||
set +x
|
||||
echo -e "$MSG"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function check_tests {
|
||||
FAIL=$(cat /tmp/out.log | grep -m 1 -Eo "([0-9]+)\s+failure" | cut -d' ' -f 1)
|
||||
TOTAL=$(cat /tmp/out.log | grep -m 1 -Eo "([0-9]+)\s+spec" | cut -d' ' -f 1)
|
||||
NOT_EXECUTED=$(cat /tmp/out.log | grep -m 1 -Eo "([0-9]+)\s+pending" | cut -d' ' -f 1)
|
||||
|
||||
# If test fail
|
||||
if [ $FAIL -gt 0 ]
|
||||
then
|
||||
TESTS_RET=1
|
||||
fi
|
||||
|
||||
# Console
|
||||
echo -e "\033[1mTests results for $1\033[0m" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
echo -e "Total : $TOTAL" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
if [ $FAIL -gt 0 ]
|
||||
then
|
||||
echo -e "\033[0;31mFailed : $FAIL\033[0m" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
else
|
||||
echo -e "Failed : $FAIL" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
fi
|
||||
echo -e "Not executed : $NOT_EXECUTED" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
if [ $FAIL -gt 0 ]
|
||||
then
|
||||
echo -e "\033[0;31mTests failed\033[0m" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
else
|
||||
echo -e "\033[0;36mTests success\033[0m" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
fi
|
||||
echo "" >> "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
|
||||
# HTML
|
||||
echo "<table style=\"margin-bottom: 10px;\"><tbody><tr><td colspan=\"3\" style=\"background-color: aquamarine;\"><strong>$1</strong></td></tr><tr>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
echo "<td>Total</td><td>Failed</td><td>Not executed</td></tr><tr>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
if [ $FAIL -gt 0 ]
|
||||
then
|
||||
echo "<td>$TOTAL</td><td style=\"color: red;\">$FAIL</td><td>$NOT_EXECUTED</td>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
echo "</tr><tr><td colspan=\"3\" style=\"color: red;\"><strong>Tests failed</strong></td>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
else
|
||||
echo "<td>$TOTAL</td><td>$FAIL</td><td>$NOT_EXECUTED</td>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
echo "</tr><tr><td colspan=\"3\" style=\"color: #170;\"><strong>Tests success</strong></td>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
fi
|
||||
echo "</tr><tr><td colspan=\"3\"><a href=\"$2.html\" target=\"_blank\">View test report</a></td>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
echo "</tr></tbody></table>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
if [ $TESTS_RET -eq 1 ]
|
||||
then
|
||||
echo -e "\033[0;31mFailed\033[0m"
|
||||
return 131
|
||||
else
|
||||
echo -e "\033[0;36mSuccess\033[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
function run_tests {
|
||||
RET=0
|
||||
USE_PKILL=$3
|
||||
|
||||
# create empty logfile
|
||||
cat /dev/null >/tmp/out.log
|
||||
|
||||
if [ "$USE_PKILL" -eq 1 ]; then
|
||||
pkill -9 sogod
|
||||
else
|
||||
service sogod stop
|
||||
fi
|
||||
# Kill residual SOGo process
|
||||
LSOF_OUT=$(lsof -i TCP@127.0.0.1 -Fp | tr -d p)
|
||||
if [ ! -z "$LSOF_OUT" ]; then
|
||||
kill -9 $LSOF_OUT
|
||||
fi
|
||||
|
||||
|
||||
# restart services
|
||||
if [ "$USE_PKILL" -eq 1 ]; then
|
||||
su -s /bin/bash -c "/usr/sbin/sogod -WOWorkersCount 3 -WOPidFile /var/run/sogo/sogo.pid -WOLogFile /var/log/sogo/sogo.log" sogo
|
||||
else
|
||||
service sogod start
|
||||
fi
|
||||
|
||||
# wait for it to settle
|
||||
sleep 3
|
||||
|
||||
# run the tests and gather output
|
||||
cd "$SRC_SOGO/Tests"
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nCan't cd into the Tests folder..."
|
||||
error_out
|
||||
fi
|
||||
npm run test-junit 2>&1 | tee -a /tmp/out.log
|
||||
|
||||
RC=$?
|
||||
GRC=$(($GRC+$RC))
|
||||
if [ $RC -ne 0 ]; then
|
||||
MSG="$MSG\nError running the integration tests"
|
||||
error_out
|
||||
fi
|
||||
|
||||
# source GNUstep.sh
|
||||
# set +x
|
||||
#. /usr/share/GNUstep/Makefiles/GNUstep.sh
|
||||
# set -x
|
||||
|
||||
# teststrings
|
||||
# run only once, no point in running with all the backend
|
||||
# substitutions
|
||||
# if [[ -z ${TEST_RUN_COUNT} || ${TEST_RUN_COUNT} -lt 1 ]]; then
|
||||
# cd Integration
|
||||
# ./teststrings.sh 2>&1 | tee -a /tmp/out.log
|
||||
# fi
|
||||
|
||||
# stop sogo when we're done
|
||||
if [ "$USE_PKILL" -eq 1 ]; then
|
||||
pkill -9 sogod
|
||||
else
|
||||
service sogod stop
|
||||
fi
|
||||
|
||||
XML_FILE="$SRC_SOGO/Tests/results/$2"
|
||||
mv /tmp/results.xml "$XML_FILE"
|
||||
|
||||
check_tests "$1" "$2"
|
||||
|
||||
# Generate JSON
|
||||
TOTAL_TESTS=$(xmllint --xpath 'sum(//testsuite/@tests)' "$XML_FILE")
|
||||
TOTAL_FAILURES=$(xmllint --xpath 'sum(//testsuite/@failures)' "$XML_FILE")
|
||||
TOTAL_ERRORS=$(xmllint --xpath 'sum(//testsuite/@errors)' "$XML_FILE")
|
||||
TOTAL_FAILED=$(($TOTAL_FAILURES + $TOTAL_ERRORS))
|
||||
TOTAL_SUCCESS=$(($TOTAL_TESTS - $TOTAL_FAILED))
|
||||
if [ "$TOTAL_FAILED" -gt 0 ]; then
|
||||
FAILED=true
|
||||
TESTS_FAILED=true
|
||||
else
|
||||
FAILED=false
|
||||
fi
|
||||
JSON_DATA=$(jq -n \
|
||||
--argjson total_tests "$TOTAL_TESTS" \
|
||||
--argjson total_failed "$TOTAL_FAILED" \
|
||||
--argjson total_success "$TOTAL_SUCCESS" \
|
||||
--arg description "$1" \
|
||||
--arg scenario "$2" \
|
||||
--argjson failed "$FAILED" \
|
||||
'{scenario: $scenario, description: $description, total_tests: $total_tests, total_failed: $total_failed, total_success: $total_success, failed: $failed}')
|
||||
TESTS_RESULTS+=("$JSON_DATA")
|
||||
}
|
||||
|
||||
test() {
|
||||
#set -x
|
||||
USE_PKILL=${1:-0}
|
||||
TESTS_FAILED=false
|
||||
TESTS_RESULTS=()
|
||||
rm -f "$JSON_TEST_RESULTS_PATH"
|
||||
if [ "${SKIP_TESTS:-0}" -eq 1 ]; then
|
||||
subsubtitle "Skipping tests"
|
||||
return 0;
|
||||
fi
|
||||
|
||||
# INTEGRATION TESTS
|
||||
if [[ -d "$SRC_SOGO/Tests/results" ]]; then
|
||||
rm -Rf "$SRC_SOGO/Tests/results"
|
||||
fi
|
||||
|
||||
mkdir -p "$SRC_SOGO/Tests/results"
|
||||
echo "" > "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
echo "<html><head><style>table, th, td {border: 1px solid darkgrey;border-collapse: collapse; width: 400px; font-family: monospace;}</style></head><body>" > "$SRC_SOGO/Tests/results/index.html"
|
||||
|
||||
test_title_color="${bold}${yellow}"
|
||||
|
||||
# MySQL
|
||||
echo "${test_title_color}Running tests with LDAP auth and MySQL backend${normal}"
|
||||
prep_tests
|
||||
prep_tests_mysql
|
||||
run_tests "Running tests with LDAP auth and MySQL backend" "results-mysql-ldap.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with MySQL auth and MySQL backend${normal}"
|
||||
prep_tests
|
||||
prep_tests_mysql
|
||||
prep_tests_mysql_auth
|
||||
run_tests "Running tests with MySQL auth and MySQL backend" "results-mysql.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with LDAP auth and MySQL backend, combined database tables${normal}"
|
||||
prep_tests
|
||||
prep_tests_mysql
|
||||
prep_tests_mysql_combined
|
||||
run_tests "Running tests with LDAP auth and MySQL backend, combined database tables" "results-mysql-ldap-combined.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with MySQL auth and MySQL backend, combined database tables${normal}"
|
||||
prep_tests
|
||||
prep_tests_mysql
|
||||
prep_tests_mysql_auth_combined
|
||||
run_tests "Running tests with MySQL auth and MySQL backend, combined database tables" "results-mysql-combined.xml" $USE_PKILL
|
||||
|
||||
|
||||
# PGSQL
|
||||
echo "${test_title_color}Running tests with LDAP auth and postgresql backend${normal}"
|
||||
prep_tests
|
||||
prep_tests_postgresql
|
||||
run_tests "Running tests with LDAP auth and postgresql backend" "results-postgresql-ldap.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with postgresql auth and postgresql backend${normal}"
|
||||
prep_tests
|
||||
prep_tests_postgresql
|
||||
prep_tests_postgresql_auth
|
||||
run_tests "Running tests with postgresql auth and postgresql backend" "results-postgresql.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with LDAP auth and postgresql backend, combined database tables${normal}"
|
||||
prep_tests
|
||||
prep_tests_postgresql
|
||||
prep_tests_postgresql_combined
|
||||
run_tests "Running tests with LDAP auth and postgresql backend, combined database tables" "results-postgresql-ldap-combined.xml" $USE_PKILL
|
||||
|
||||
echo "${test_title_color}Running tests with postgresql auth and postgresql backend, combined database tables${normal}"
|
||||
prep_tests
|
||||
prep_tests_postgresql
|
||||
prep_tests_postgresql_auth_combined
|
||||
run_tests "Running tests with postgresql auth and postgresql backend, combined database tables" "results-postgresql-combined.xml" $USE_PKILL
|
||||
|
||||
|
||||
# set -x
|
||||
|
||||
# JUnit
|
||||
for file in $SRC_SOGO/Tests/results/*.xml #$xmlfiles
|
||||
do
|
||||
xunit-viewer -r $file -c -o "$file.html"
|
||||
done
|
||||
cat "$SRC_SOGO/Tests/results/tests_results.txt"
|
||||
echo "</body>" >> "$SRC_SOGO/Tests/results/index.html"
|
||||
chown 644 -R "$SRC_SOGO/Tests/results"
|
||||
chown -R www-data:www-data "$SRC_SOGO/Tests/results"
|
||||
|
||||
# Restore conf
|
||||
rm /etc/sogo/sogo.conf
|
||||
cp /etc/sogo/sogo-base.conf /etc/sogo/sogo.conf
|
||||
if [ "$USE_PKILL" -eq 1 ]; then
|
||||
pkill -9 sogod
|
||||
su -s /bin/bash -c "/usr/sbin/sogod -WOWorkersCount 3 -WOPidFile /var/run/sogo/sogo.pid -WOLogFile /var/log/sogo/sogo.log" sogo
|
||||
else
|
||||
service sogod restart > /dev/null
|
||||
fi
|
||||
|
||||
# Global json results
|
||||
TESTS_RESULTS_JSON=$(printf '%s\n' "${TESTS_RESULTS[@]}" | jq -s .)
|
||||
FINAL_JSON=$(jq -n \
|
||||
--argjson tests_failed "$TESTS_FAILED" \
|
||||
--argjson tests "$TESTS_RESULTS_JSON" \
|
||||
'{failed: $tests_failed, tests: $tests}')
|
||||
echo "$FINAL_JSON" > $JSON_TEST_RESULTS_PATH
|
||||
|
||||
result_link="${bold}${magenta}--------------------------------------------------\nTests results : https://127.0.0.1/tests/index.html${normal}"
|
||||
|
||||
# If test fail
|
||||
if [ $TESTS_RET -eq 1 ]
|
||||
then
|
||||
echo -e "$result_link [${bold}${red}Failed${normal}]\n"
|
||||
return 131
|
||||
else
|
||||
echo -e "$result_link [${bold}${green}Success${normal}]\n"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
cd ${WORKSPACE} \
|
||||
./configure --enable-debug --disable-strip --enable-mfa \
|
||||
make \
|
||||
make install \
|
||||
echo "register sogo library" \
|
||||
echo "/usr/local/lib/sogo" > /etc/ld.so.conf.d/sogo.conf \
|
||||
ldconfig \
|
||||
echo "create directories and enforce permissions" \
|
||||
install -o sogo -g sogo -m 755 -d /var/run/sogo \
|
||||
install -o sogo -g sogo -m 750 -d /var/spool/sogo \
|
||||
install -o sogo -g sogo -m 750 -d /var/log/sogo
|
||||
|
||||
su -s /bin/bash - sogo -c "echo \"set debuginfod enabled off\" >> ~/.gdbinit"
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SRC_SOPE=/src/SOPE/
|
||||
SRC_SOGO=/src/SOGo/
|
||||
|
||||
source /include/common.sh $SRC_SOPE $SRC_SOGO
|
||||
|
||||
options="h:b:ba:br:d"
|
||||
long_options="help,build,build-all,build-resources,debug"
|
||||
parsed_options=$(getopt -o $options -l $long_options)
|
||||
|
||||
# Check for errors in parsing
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Evaluate the parsed options
|
||||
#eval set -- "$parsed_options"
|
||||
|
||||
help() {
|
||||
echo "${green} ----------------------"
|
||||
echo "| ${bold}SOGo Dev env${normal}${green} |"
|
||||
echo " ----------------------"
|
||||
echo
|
||||
echo "${normal}Options are :${cyan}"
|
||||
|
||||
echo -e "-h, --help\t\tShow help"
|
||||
echo -e "-b, --build\t\tBuild sogo app"
|
||||
echo -e "-ba, --build-all\tClean, build sogo and sope"
|
||||
echo -e "-br, --build-resources\tBuild only sogo JS/CSS resources"
|
||||
echo -e "-d, --debug\t\tStart sogo in debug with gdb"
|
||||
echo "${normal}"
|
||||
}
|
||||
|
||||
ssl_fix() {
|
||||
if [[ -z "${LD_PRELOAD}" ]]; then
|
||||
LIBSSL_LOCATION=$(find / -type f -name "libssl.so.*" -print -quit);echo "LD_PRELOAD=$LIBSSL_LOCATION" >> /etc/default/sogo
|
||||
echo "LD_LIBRARY_PATH=/usr/local/lib/sogo:/usr/local/lib:$LD_LIBRARY_PATH" >> /etc/default/sogo
|
||||
export LD_PRELOAD=$LIBSSL_LOCATION
|
||||
else
|
||||
echo "LD_PRELOAD=$LD_PRELOAD" >> /etc/default/sogo
|
||||
echo "LD_LIBRARY_PATH=/usr/local/lib/sogo:/usr/local/lib:$LD_LIBRARY_PATH" >> /etc/default/sogo
|
||||
export LD_PRELOAD=$LD_PRELOAD
|
||||
fi
|
||||
}
|
||||
|
||||
build_resources() {
|
||||
cd $SRC_SOGO
|
||||
npm config set loglevel=error
|
||||
git config --global --add safe.directory '*'
|
||||
cd UI/WebServerResources
|
||||
make dev
|
||||
make install
|
||||
}
|
||||
|
||||
build_sogo() {
|
||||
service sogod stop
|
||||
ssl_fix
|
||||
cd $SRC_SOGO
|
||||
cd ActiveSync
|
||||
make && make install
|
||||
cd ..
|
||||
./configure --enable-saml2 --enable-debug --disable-strip --enable-mfa
|
||||
make
|
||||
make install
|
||||
build_resources
|
||||
RC=$?
|
||||
if [ $RC -ne 0 ]; then
|
||||
exit $RC
|
||||
fi
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
service sogod start
|
||||
fi
|
||||
}
|
||||
|
||||
build_all() {
|
||||
service sogod stop
|
||||
cd $SRC_SOPE
|
||||
make clean
|
||||
./configure --with-gnustep --enable-debug --disable-strip
|
||||
make
|
||||
make install
|
||||
cd $SRC_SOGO
|
||||
cd ActiveSync
|
||||
make clean
|
||||
cd ..
|
||||
make clean
|
||||
build_sogo
|
||||
RC=$?
|
||||
if [ $RC -ne 0 ]; then
|
||||
exit $RC
|
||||
fi
|
||||
}
|
||||
|
||||
debug() {
|
||||
build_sogo "norestart"
|
||||
echo "${magenta}================"
|
||||
echo "GDB reminders :"
|
||||
echo " * run : Run app (set breakpoints before)"
|
||||
echo " * break SOGo.m:494 : Add breakpoint example"
|
||||
echo " * c : continue"
|
||||
echo " * n : next"
|
||||
echo " * list 504 : show lines around"
|
||||
echo " * p var : print variable 'var'"
|
||||
echo " * po var : print object 'var'"
|
||||
echo " * bt : Show stacktrace"
|
||||
echo " * bt full : Show stacktrace with all vars"
|
||||
echo "================${normal}"
|
||||
echo ""
|
||||
|
||||
su -s /bin/bash - sogo -c "gdb --args /usr/local/sbin/sogod -WOUseWatchDog NO -WONoDetach YES -WOPort 0.0.0.0:50000 -WOWorkersCount 1 -WOPidFile /var/run/sogo/sogo.pid"
|
||||
}
|
||||
|
||||
# Process the options
|
||||
while true; do
|
||||
case "$1" in
|
||||
-b|--build)
|
||||
build_sogo
|
||||
exit 0
|
||||
;;
|
||||
-ba|--build-all)
|
||||
build_all
|
||||
exit 0
|
||||
;;
|
||||
-br|--build-resources)
|
||||
build_resources
|
||||
exit 0
|
||||
;;
|
||||
-d|--debug)
|
||||
debug
|
||||
exit 0
|
||||
;;
|
||||
-h|--help)
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
@@ -1,53 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
green=$(tput setaf 2)
|
||||
white=$(tput setaf 7)
|
||||
magenta=$(tput setaf 5)
|
||||
cyan=$(tput setaf 6)
|
||||
underline=$(tput smul)
|
||||
no_underline=$(tput rmul)
|
||||
|
||||
cd /src/SOGo
|
||||
|
||||
echo "${white} "
|
||||
echo "${white} "
|
||||
echo "${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒${white} ${green}▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒${white} ${green}▒▒▒▒${white} "
|
||||
echo "${white} ${green}▒▒▒▒▒▒▒▒▒▒${white} "
|
||||
echo "${white} "
|
||||
echo "${white} ${bold}${green}DEVELOPER${normal} "
|
||||
echo "${white} "
|
||||
echo "${bold}${magenta}Access : https://127.0.0.1/SOGo/${normal}"
|
||||
echo "${bold}${cyan}Use ${underline}devenv${no_underline} command to start${normal}"
|
||||
echo ""
|
||||
|
||||
HAS_OLD_SOGO_INSTANCE=$(find /usr/local/lib/sogo/ -type f -name libSOGoUI.so.* | wc -l)
|
||||
if [ "$HAS_OLD_SOGO_INSTANCE" -gt 1 ]; then
|
||||
echo "${bold}${red}/!\ You have an instable dev environment (two sogo libraries versions). This can be caused by a disynchronized SOGo code source (docker and local environment) This can be fixed by updating your local git repositories, delete and rebuild docker compose. You can also run devenv -ba.${normal}"
|
||||
fi
|
||||
|
||||
|
||||
/etc/init.d/sogod restart
|
||||
# Run for ever
|
||||
tail -f /dev/null
|
||||
@@ -1,107 +0,0 @@
|
||||
{
|
||||
/* ********************* Main SOGo configuration file **********************
|
||||
* *
|
||||
* Since the content of this file is a dictionary in OpenStep plist format, *
|
||||
* the curly braces enclosing the body of the configuration are mandatory. *
|
||||
* See the Installation Guide for details on the format. *
|
||||
* *
|
||||
* C and C++ style comments are supported. *
|
||||
* *
|
||||
* This example configuration contains only a subset of all available *
|
||||
* configuration parameters. Please see the installation guide more details. *
|
||||
* *
|
||||
* ~sogo/GNUstep/Defaults/.GNUstepDefaults has precedence over this file, *
|
||||
* make sure to move it away to avoid unwanted parameter overrides. *
|
||||
* *
|
||||
* **************************************************************************/
|
||||
|
||||
/* Database configuration (mysql://, postgresql:// or oracle://) */
|
||||
WOPort = "0.0.0.0:50000";
|
||||
|
||||
|
||||
// MySQL
|
||||
SOGoProfileURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_user_profile";
|
||||
OCSFolderInfoURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_folder_info";
|
||||
OCSSessionsFolderURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_sessions_folder";
|
||||
OCSEMailAlarmsFolderURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_alarms_folder";
|
||||
OCSCacheFolderURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_cache_folder";
|
||||
OCSStoreURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_store";
|
||||
OCSAclURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_acl";
|
||||
|
||||
|
||||
//Password
|
||||
SOGoPasswordChangeEnabled = YES;
|
||||
SOGoPasswordRecoveryEnabled = YES;
|
||||
|
||||
SOGoFirstWeekOfYear = "January1";
|
||||
WOWorkersCount = 10;
|
||||
WOWatchDogRequestTimeout = 5;
|
||||
WOListenQueueSize = 15;
|
||||
|
||||
SOGoUserSources = (
|
||||
{
|
||||
CNFieldName = cn;
|
||||
IDFieldName = uid;
|
||||
UIDFieldName = uid;
|
||||
baseDN = "ou=users,dc=example,dc=org";
|
||||
bindDN = "cn=admin,dc=example,dc=org";
|
||||
bindPassword = "password";
|
||||
canAuthenticate = YES;
|
||||
displayName = "Shared Addresses";
|
||||
hostname = "openldap";
|
||||
id = public;
|
||||
isAddressBook = YES;
|
||||
port = 389;
|
||||
KindFieldName = description;
|
||||
MultipleBookingsFieldName="departmentNumber";
|
||||
}
|
||||
);
|
||||
|
||||
SOGoDisableSharing = ();
|
||||
SOGoDisableExport = ();
|
||||
SOGoDisableSharingAnyAuthUser = ();
|
||||
|
||||
|
||||
//Identities
|
||||
SOGoMailAuxiliaryUserAccountsEnabled = YES;
|
||||
|
||||
SOGoPageTitle = NewName;
|
||||
SOGoSieveScriptsEnabled = YES;
|
||||
SOGoForwardEnabled = YES;
|
||||
SOGoNotificationEnabled = YES;
|
||||
SOGoVacationEnabled = YES;
|
||||
SOGoEnableEMailAlarms = YES;
|
||||
SOGoEnablePublicAccess = YES;
|
||||
SOGoTimeZone = Europe/Paris;
|
||||
SOGoIMAPServer = "imapd:143";
|
||||
NGImap4AuthMechanism = "plain";
|
||||
SOGoSieveServer = "sieve://imapd:4190";
|
||||
SOGoMailingMechanism = smtp;
|
||||
SOGoSMTPServer = "smtpd";
|
||||
SOGoCalendarDefaultRoles = ("PublicDAndTViewer");
|
||||
SOGoAppointmentSendEMailNotifications = YES;
|
||||
SOGoMailDomain = "example.org";
|
||||
SOGoLanguage = "English";
|
||||
SOGoSuperUsernames = ("sogo-tests-super");
|
||||
SOGoCalendarDefaultRoles = ("PublicDAndTViewer");
|
||||
SOGoMemcachedHost = "memcached";
|
||||
SOGoXSRFValidationEnabled = NO;
|
||||
|
||||
NGImap4ConnectionStringSeparator = "/";
|
||||
|
||||
|
||||
|
||||
|
||||
/* Debug */
|
||||
SoDebugBaseURL = YES;
|
||||
SOGoDebugRequests = YES;
|
||||
ImapDebugEnabled = YES;
|
||||
LDAPDebugEnabled = YES;
|
||||
PGDebugEnabled = YES;
|
||||
SMTPDebugEnabled = YES;
|
||||
MySQL4DebugEnabled = YES;
|
||||
SOGoUIxDebugEnabled = YES;
|
||||
WOLogFile = /var/log/sogo/sogo.log;
|
||||
SOGoDebugLeaks = YES;
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile
|
||||
{
|
||||
"name": "sogo",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "sogo",
|
||||
"workspaceFolder": "/workspace",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
services:
|
||||
memcached:
|
||||
image: memcached:1.6
|
||||
container_name: sogo_memcached
|
||||
restart: unless-stopped
|
||||
httpd:
|
||||
build:
|
||||
context: ./conf/httpd/
|
||||
dockerfile: Dockerfile
|
||||
container_name: sogo_httpd
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- sogo
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- ./conf/httpd/ssl:/ssl
|
||||
- ./conf/httpd/CanadaHolidays.ics:/usr/local/apache2/htdocs/CanadaHolidays.ics
|
||||
- sogo-static-files:/usr/local/lib/GNUstep
|
||||
mariadb:
|
||||
image: mariadb:11
|
||||
container_name: sogo_mariadb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
MYSQL_DATABASE: db
|
||||
ports:
|
||||
- 3307:3306
|
||||
volumes:
|
||||
- sogo-mariadb:/var/lib/mysql
|
||||
- ./conf/db/mysql.sql:/docker-entrypoint-initdb.d/init-sogo.sql
|
||||
openldap:
|
||||
image: bitnami/openldap:2.5
|
||||
container_name: sogo_openldap
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "389:389"
|
||||
environment:
|
||||
LDAP_PORT_NUMBER: 389
|
||||
LDAP_ADMIN_USERNAME: "admin"
|
||||
LDAP_ADMIN_PASSWORD: "password"
|
||||
LDAP_BIND_PASSWORD: "password"
|
||||
LDAP_ROOT: "dc=example,dc=org"
|
||||
LDAP_ADMIN_DN: "cn=admin,dc=example,dc=org"
|
||||
LDAP_CUSTOM_LDIF_DIR: "/ldifs"
|
||||
#BITNAMI_DEBUG: true
|
||||
volumes:
|
||||
- ./conf/ldap/users.ldif:/ldifs/users.ldif # User data
|
||||
imapd: # Dovecot
|
||||
build:
|
||||
context: ./conf/dovecot/
|
||||
dockerfile: Dockerfile
|
||||
container_name: sogo_dovecot
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- openldap
|
||||
ports:
|
||||
- "143:143"
|
||||
- "993:993"
|
||||
- "4190:4190"
|
||||
- "24:24"
|
||||
volumes:
|
||||
- sogo-mail-data:/var/mail
|
||||
- sogo-sieve-data:/var/sieve
|
||||
smtpd: # Postfix
|
||||
build:
|
||||
context: ./conf/postfix/
|
||||
dockerfile: Dockerfile
|
||||
container_name: sogo_postfix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "25:25"
|
||||
depends_on:
|
||||
- imapd
|
||||
- openldap
|
||||
entrypoint: /entrypoint.sh
|
||||
sogo:
|
||||
container_name: sogo_dev
|
||||
restart: unless-stopped
|
||||
tty: true
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: .devcontainer/Dockerfile.devcontainer
|
||||
ports:
|
||||
- 50000:50000
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
depends_on:
|
||||
- openldap
|
||||
- memcached
|
||||
- mariadb
|
||||
- imapd
|
||||
- smtpd
|
||||
volumes:
|
||||
- ..:/workspace
|
||||
- sogo-static-files:/usr/local/lib/GNUstep
|
||||
- ./conf/sogo/sogo.conf:/etc/sogo/sogo.conf
|
||||
# - /path/to/sope_folder:/src/SOPE # Uncomment this line if you want to mount SOPE source code
|
||||
|
||||
volumes:
|
||||
sogo-mariadb:
|
||||
sogo-postgres:
|
||||
sogo-mail-data:
|
||||
sogo-sieve-data:
|
||||
sogo-static-files:
|
||||
@@ -1,74 +0,0 @@
|
||||
## Dev Container
|
||||
|
||||
The SOGo dev container will deploy a complete environnement to work and test with SOGo
|
||||
|
||||
This environnement contains:
|
||||
- a mariadb database
|
||||
- an imap server (dovecot) and a smtp server (postfix)
|
||||
- a ldap server for the user source
|
||||
- an Apache server
|
||||
- The SOGo instance
|
||||
|
||||
## How to use the devcontainer
|
||||
|
||||
Simply clone the source code of the SOGo repo and open id with Visual Code Studio. If this is not already the case, you will need the [Dev Container Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). Then, simply execute the command "New Dev COntainer" and VCS will start building it.
|
||||
|
||||
|
||||
When it's all build, go to http://127.0.0.1/SOGo. You have 3 users to login with:
|
||||
`sogo-tests1`, `sogo-tests2`, `sogo-tests3` with all the same password `sogo`
|
||||
|
||||
You can only send mail and receive mail among those three users.
|
||||
|
||||
**If you have troubles, you may need to build sogo once, see the next section for that.**
|
||||
|
||||
## How to work on SOGo
|
||||
|
||||
|
||||
### To modify the source and build
|
||||
|
||||
After modifyng the source in VCS, in your container's terminalthere is a command tool `devenv` with following options for building:
|
||||
```
|
||||
-b, --build Build sogo app
|
||||
-ba, --build-all Clean, build sogo and sope
|
||||
-br, --build-resources Build only sogo JS/CSS resources
|
||||
```
|
||||
|
||||
To build sogo simplye does
|
||||
```shell
|
||||
sudo devenv -b
|
||||
```
|
||||
- The options -br will only build the front
|
||||
- The options -ba will also build [SOPE](https://github.com/Alinto/sope) (low-level of SOGo, needs to be build before SOGo)
|
||||
|
||||
|
||||
### To use the debugger
|
||||
|
||||
Inside the sogo container there is a tool to launch SOGo with the [debugger gdb](https://sourceware.org/gdb/).
|
||||
|
||||
Use one of the following command:
|
||||
|
||||
```shell
|
||||
sudo devenv -d
|
||||
sudo devenv --debug
|
||||
```
|
||||
|
||||
|
||||
### To change sogo.conf
|
||||
|
||||
The sogo.conf is linked to the one here [.devcontainer/conf/sogo/sogo.conf](conf/sogo/sogo.conf)
|
||||
|
||||
Modify it as you wish then you need to restart the sogo service inside the container:
|
||||
```shell
|
||||
service sogod restart
|
||||
```
|
||||
|
||||
### To modify SOPE
|
||||
|
||||
Sometimes, you may have to change SOPE source code. In order to do that:
|
||||
- First, clone the SOPE repo locally.
|
||||
- Uncomment line 101 of the docker-compose.yml file and put the correct path to your SOPE folder. It should end with 'sope' like this: `/home/myuser/github/sope`
|
||||
- Then, you have to rebuild your devcontainer.
|
||||
- Now you can modify the source of SOPE and build it by going inside the sogo_dev container and do.
|
||||
```shell
|
||||
sudo devenv -ba
|
||||
```
|
||||
@@ -1,140 +0,0 @@
|
||||
# Contributing to SOGo
|
||||
|
||||
## Reporting Bugs and Suggesting Enhancements
|
||||
|
||||
If you encounter a possible bug with SOGo, you can access our
|
||||
[bug tracking system](https://bugs.sogo.nu/).
|
||||
|
||||
Please make sure to respect the following guidelines when reporting a bug:
|
||||
|
||||
* verify that the bug you found is not already known or even fixed in the `master` version
|
||||
* make the actual facts very clear; be precise, we need to be able to reproduce the problem
|
||||
* explain your speculations, if any
|
||||
* add a screenshot to the ticket if appropriate
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
Begin by reading [SOGo Developer's Guide](../Documentation/SOGoDevelopersGuide.asciidoc).
|
||||
|
||||
### Translations
|
||||
|
||||
Three type of files must be translated. The first type are **Localizable.strings**; they can be
|
||||
translated online using **[Transifex](https://www.transifex.com/alinto/sogo/)**. To use Transifex,
|
||||
you must first sign up for a [free account](https://www.transifex.com/signup/). Once registered,
|
||||
[request a new team](https://www.transifex.com/alinto/teams/) for your language. Once authorized,
|
||||
you'll be able to start/continue translating SOGo in your language.
|
||||
|
||||
The second type are **wox and html templates**. Only words outside the tags (<>) must be
|
||||
translated. Start by duplicating the English templates:
|
||||
|
||||
* [UI/Templates/SOGoACLEnglishAdditionAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishAdditionAdvisory.wox)
|
||||
* [UI/Templates/SOGoACLEnglishRemovalAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishRemovalAdvisory.wox)
|
||||
* [UI/Templates/SOGoACLEnglishModificationAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishModificationAdvisory.wox)
|
||||
* [UI/Templates/SOGoFolderEnglishAdditionAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoFolderEnglishAdditionAdvisory.wox)
|
||||
* [UI/Templates/SOGoFolderEnglishRemovalAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoFolderEnglishRemovalAdvisory.wox)
|
||||
* [SoObjects/Mailer/SOGoMailEnglishForward.wo/SOGoMailEnglishForward.html](https://raw.githubusercontent.com/alinto/sogo/master/SoObjects/Mailer/SOGoMailEnglishForward.wo/SOGoMailEnglishForward.html)
|
||||
* [SoObjects/Mailer/SOGoMailEnglishReply.wo/SOGoMailEnglishReply.html](https://raw.githubusercontent.com/alinto/sogo/master/SoObjects/Mailer/SOGoMailEnglishReply.wo/SOGoMailEnglishReply.html)
|
||||
|
||||
The third type is the locale file formatted as a **plist**. Duplicate the English locale. Beware that words with other characters than [a-zA-Z] (accents, non-latin...) must be between double quotes ("). You can look at other files as arabic or french to have an example:
|
||||
|
||||
* [UI/MainUI/English.lproj/Locale](https://raw.githubusercontent.com/alinto/sogo/master/UI/MainUI/English.lproj/Locale)
|
||||
|
||||
Once translated, create an archive with all the files and [contact
|
||||
us](https://sogo.nu/support.html#/commercial). We'll integrate it in the next version of SOGo.
|
||||
|
||||
### Git Commit Guidelines
|
||||
|
||||
We have very precise rules over how our git commit messages can be formatted. This leads to **more
|
||||
readable messages** that are easy to follow when looking through the **project history**.
|
||||
|
||||
It is important to note that we use the git commit messages to **generate** the
|
||||
[CHANGELOG](../CHANGELOG.md) document. Improperly formatted commit messages may result in your
|
||||
change not appearing in the CHANGELOG of the next release.
|
||||
|
||||
### Commit Message Format
|
||||
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
|
||||
format that includes a **type**, a **scope** and a **subject**:
|
||||
|
||||
```html
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<footer>
|
||||
```
|
||||
|
||||
> Any line of the commit message cannot be longer than 100 characters.
|
||||
> This allows the message to be easier to read on GitHub as well as in various Git tools.
|
||||
|
||||
#### Type
|
||||
Must be one of the following:
|
||||
|
||||
* **feat**: A new feature
|
||||
* **fix**: A bug fix
|
||||
* **docs**: Documentation only changes
|
||||
* **i18n**: Change in localizable strings
|
||||
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
|
||||
semi-colons, etc)
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build and packaging process or auxiliary tools (sogo-tool,
|
||||
sogo-ealarms-notify) and libraries such as documentation generation
|
||||
|
||||
#### Scope
|
||||
The scope could be anything that helps specifying the scope (or feature) that is changing.
|
||||
|
||||
Examples
|
||||
|
||||
* mail
|
||||
* mail(js)
|
||||
* calendar(css)
|
||||
* addressbook
|
||||
* preferences(js)
|
||||
* core
|
||||
* eas
|
||||
|
||||
#### Subject
|
||||
The subject contains a succinct description of the change:
|
||||
|
||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
* don't capitalize first letter
|
||||
* no dot (.) at the end
|
||||
|
||||
#### Body
|
||||
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
The body should include the motivation for the change and contrast this with previous behavior.
|
||||
|
||||
#### Footer
|
||||
The footer should contain any information about **Breaking Changes** and is also the
|
||||
place to reference [Mantis](https://bugs.sogo.nu) issues that this commit **Fixes** or **Resolves**.
|
||||
|
||||
> Breaking Changes are intended to be highlighted in the CHANGELOG as changes that will require
|
||||
> community users to modify their code after updating to a version that contains this commit.
|
||||
|
||||
#### Sample Commit messages
|
||||
```text
|
||||
fix(calendar): don't raise exception when renaming with same name
|
||||
|
||||
this would break Apple Calendar.app when creating a new calendar
|
||||
|
||||
Fixes #4813
|
||||
```
|
||||
```text
|
||||
feat(calendar(js)): optionally expand LDAP groups in attendees editor
|
||||
|
||||
* add `/members` action for LDIF groups
|
||||
* add button to expand invited LDAP groups
|
||||
|
||||
Fixes #2506
|
||||
```
|
||||
```text
|
||||
fix(core): set default Sieve port to 4190
|
||||
|
||||
BREAKING CHANGE: the default port for the SOGoSieveServer configuration default is now 4190 (was
|
||||
2000).
|
||||
|
||||
You need to explicitly set the port if you use a different port.
|
||||
|
||||
Closes #4826
|
||||
```
|
||||
+13
-56
@@ -1,61 +1,18 @@
|
||||
config.make
|
||||
tags
|
||||
*._*
|
||||
*.css
|
||||
*.pyc
|
||||
*.sax
|
||||
*.swp
|
||||
*.wox/
|
||||
*/*/*.SOGo/
|
||||
*/*/*/obj/
|
||||
*/*/obj/
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
ActiveSync/ActiveSync.SOGo
|
||||
API/API.SOGo
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
Documentation/*.html
|
||||
*._*
|
||||
*/*/obj/
|
||||
*/*/*/obj/
|
||||
*/*/*.SOGo/
|
||||
*.sax
|
||||
*.wox/
|
||||
*.swp
|
||||
SoObjects/SOGo/SOGo.framework/
|
||||
SoObjects/SOGo/derived_src/
|
||||
Tests/*/config.py
|
||||
UI/WebServerResources/.bowerrc
|
||||
UI/WebServerResources/.sass-cache/
|
||||
UI/WebServerResources/bower_components/
|
||||
UI/WebServerResources/css/
|
||||
UI/WebServerResources/js/*.js
|
||||
UI/WebServerResources/js/*.js.map
|
||||
UI/WebServerResources/js/vendor/*.js
|
||||
UI/WebServerResources/js/vendor/*.js.map
|
||||
UI/WebServerResources/node_modules/
|
||||
UI/WebServerResources/scss/.sass-cache/
|
||||
config.make
|
||||
doc
|
||||
tags
|
||||
.DS_Store
|
||||
Tests/package-lock.json
|
||||
.vscode
|
||||
.configure-test*
|
||||
UI/WebServerResources/package-lock.json
|
||||
|
||||
# CKEditor
|
||||
UI/WebServerResources/js/vendor/ckeditor/samples/
|
||||
UI/WebServerResources/js/vendor/ckeditor/skins/n1theme/readme.md
|
||||
UI/WebServerResources/js/vendor/ckeditor/*.md
|
||||
UI/WebServerResources/js/vendor/ckeditor/adapters/jquery.js
|
||||
UI/WebServerResources/js/vendor/ckeditor/bender-runner.config.json
|
||||
UI/WebServerResources/js/vendor/ckeditor/plugins/onchange/docs
|
||||
UI/WebServerResources/js/vendor/ckeditor/plugins/scayt/*.md
|
||||
UI/WebServerResources/js/vendor/ckeditor/skins/n1theme/*.md
|
||||
|
||||
# Transifex
|
||||
.tx/config_20230213185112.bak
|
||||
|
||||
# Tests
|
||||
Tests/node_modules
|
||||
Tests/lib/config.js
|
||||
Tests/results.xml
|
||||
Tests/results
|
||||
|
||||
# SAML2 autogenerated files
|
||||
SoObjects/SOGo/SOGoSAML2Exceptions.*
|
||||
|
||||
node_modules
|
||||
*.pyc
|
||||
._*
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "UI/WebServerResources/angular-material"]
|
||||
path = UI/WebServerResources/angular-material
|
||||
url = https://github.com/Alinto/material.git
|
||||
+275
-47
@@ -1,60 +1,288 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = fr: French, pt_BR: BrazilianPortuguese, ru: Russian, sk: Slovak, es_AR: SpanishArgentina, fi: Finnish, id_ID: Indonesian, lt: Lithuanian, tr_TR: TurkishTurkey, zh_TW: ChineseTaiwan, ar: Arabic, cs: Czech, nn_NO: NorwegianNynorsk, sl_SI: Slovenian, uk: Ukrainian, zh_CN: ChineseChina, sv: Swedish, bg_BG: Bulgarian, cy: Welsh, is: Icelandic, sr: Serbian, lv: Latvian, pl: Polish, ro_RO: Romanian, bs_BA: Bosnian,ca: Catalan, he: Hebrew, kk: Kazakh, pt: Portuguese, es_ES: SpanishSpain, eu: Basque, hu: Hungarian, ja: Japanese, mk_MK: Macedonian, nb_NO: NorwegianBokmal, nl: Dutch, sr@latin: SerbianLatin, da_DK: Danish, de: German, hr_HR: Croatian, it: Italian, sr_ME@latin: Montenegrin, gl_ES: Galician, ko: Korean, th: Thai, el: Greek
|
||||
|
||||
[o:alinto:p:sogo:r:soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = SoObjects/Appointments/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-mailerui]
|
||||
source_file = UI/MailerUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/MailerUI/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/MailerUI/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/MailerUI/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/MailerUI/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/MailerUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MailerUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MailerUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MailerUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MailerUI/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MailerUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MailerUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-preferencesui]
|
||||
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/PreferencesUI/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/PreferencesUI/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/PreferencesUI/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/PreferencesUI/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/PreferencesUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/PreferencesUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/PreferencesUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/PreferencesUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/PreferencesUI/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/PreferencesUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/PreferencesUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:soobjects-contacts]
|
||||
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = SoObjects/Contacts/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-scheduler]
|
||||
source_file = UI/Scheduler/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/Scheduler/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/Scheduler/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/Scheduler/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/Scheduler/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/Scheduler/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Scheduler/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Scheduler/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Scheduler/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Scheduler/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Scheduler/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Scheduler/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Scheduler/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:soobjects-mailer]
|
||||
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = SoObjects/Mailer/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-contacts]
|
||||
source_file = UI/Contacts/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/Contacts/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/Contacts/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/Contacts/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/Contacts/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/Contacts/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Contacts/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Contacts/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Contacts/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Contacts/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Contacts/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Contacts/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Contacts/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-administrationui]
|
||||
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/AdministrationUI/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-mainui]
|
||||
source_file = UI/MainUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/MainUI/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/MainUI/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/MainUI/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/MainUI/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/MainUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MainUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MainUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MainUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MainUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MainUI/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MainUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MainUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MainUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-common]
|
||||
source_file = UI/Common/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/Common/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-common]
|
||||
source_file = UI/Common/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/Common/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/Common/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/Common/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/Common/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/Common/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Common/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Common/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Common/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Common/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Common/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Common/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Common/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Common/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-contacts]
|
||||
source_file = UI/Contacts/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/Contacts/<lang>.lproj/Localizable.strings
|
||||
[sogo.ui-administrationui]
|
||||
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/AdministrationUI/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/AdministrationUI/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/AdministrationUI/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/AdministrationUI/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/AdministrationUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/AdministrationUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/AdministrationUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/AdministrationUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/AdministrationUI/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/AdministrationUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/AdministrationUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/AdministrationUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-mailerui]
|
||||
source_file = UI/MailerUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/MailerUI/<lang>.lproj/Localizable.strings
|
||||
[sogo.soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = SoObjects/Appointments/Arabic.lproj/Localizable.strings
|
||||
trans.ca = SoObjects/Appointments/Catalan.lproj/Localizable.strings
|
||||
trans.cs = SoObjects/Appointments/Czech.lproj/Localizable.strings
|
||||
trans.cy = SoObjects/Appointments/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = SoObjects/Appointments/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Appointments/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Appointments/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Appointments/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Appointments/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Appointments/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Appointments/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Appointments/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-mailpartviewers]
|
||||
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/MailPartViewers/<lang>.lproj/Localizable.strings
|
||||
[sogo.soobjects-contacts]
|
||||
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = SoObjects/Contacts/Arabic.lproj/Localizable.strings
|
||||
trans.ca = SoObjects/Contacts/Catalan.lproj/Localizable.strings
|
||||
trans.cs = SoObjects/Contacts/Czech.lproj/Localizable.strings
|
||||
trans.cy = SoObjects/Contacts/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = SoObjects/Contacts/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Contacts/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Contacts/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Contacts/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Contacts/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Contacts/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Contacts/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-mainui]
|
||||
source_file = UI/MainUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/MainUI/<lang>.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-preferencesui]
|
||||
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/PreferencesUI/<lang>.lproj/Localizable.strings
|
||||
|
||||
[o:alinto:p:sogo:r:ui-scheduler]
|
||||
source_file = UI/Scheduler/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
file_filter = UI/Scheduler/<lang>.lproj/Localizable.strings
|
||||
[sogo.soobjects-mailer]
|
||||
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = SoObjects/Mailer/Arabic.lproj/Localizable.strings
|
||||
trans.ca = SoObjects/Mailer/Catalan.lproj/Localizable.strings
|
||||
trans.cs = SoObjects/Mailer/Czech.lproj/Localizable.strings
|
||||
trans.cy = SoObjects/Mailer/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mailpartviewers]
|
||||
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = UI/MailPartViewers/Arabic.lproj/Localizable.strings
|
||||
trans.ca = UI/MailPartViewers/Catalan.lproj/Localizable.strings
|
||||
trans.cs = UI/MailPartViewers/Czech.lproj/Localizable.strings
|
||||
trans.cy = UI/MailPartViewers/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = UI/MailPartViewers/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MailPartViewers/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MailPartViewers/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MailPartViewers/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MailPartViewers/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MailPartViewers/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MailPartViewers/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MailPartViewers/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
|
||||
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
|
||||
@@ -1,27 +0,0 @@
|
||||
const tracker = {
|
||||
filename: "Version",
|
||||
updater: require("./Scripts/standard-version-updater.js")
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
tagPrefix: "SOGo-",
|
||||
issueUrlFormat: "https://bugs.sogo.nu/view.php?id={{id}}",
|
||||
compareUrlFormat: "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}",
|
||||
types: [
|
||||
{type: "feat", section: "Features"},
|
||||
{type: "refactor", section: "Enhancements"},
|
||||
{type: "perf", section: "Enhancements"},
|
||||
{type: "i18n", section: "Localization"},
|
||||
{type: "fix", section: "Bug Fixes"},
|
||||
{type: "chore", hidden: true},
|
||||
{type: "docs", hidden: true},
|
||||
{type: "style", hidden: true},
|
||||
{type: "test", hidden: true}
|
||||
],
|
||||
skip: {
|
||||
commit: true,
|
||||
tag: true
|
||||
},
|
||||
packageFiles: [tracker],
|
||||
bumpFiles: [tracker]
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
# GNUstep makefile
|
||||
|
||||
include common.make
|
||||
|
||||
BUNDLE_NAME = API
|
||||
|
||||
API_PRINCIPAL_CLASS = SOGoAPIProduct
|
||||
|
||||
API_OBJC_FILES = \
|
||||
SOGoAPIProduct.m \
|
||||
SOGoAPI.m \
|
||||
SOGoAPIVersion.m \
|
||||
SOGoAPIUserFolder.m \
|
||||
SOGoAPIDispatcher.m
|
||||
|
||||
API_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
API_LANGUAGES = $(SOGO_LANGUAGES)
|
||||
|
||||
API_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
||||
@@ -1,16 +0,0 @@
|
||||
# compile settings
|
||||
|
||||
ADDITIONAL_CPPFLAGS += \
|
||||
-DSOGO_MAJOR_VERSION=$(MAJOR_VERSION) \
|
||||
-DSOGO_MINOR_VERSION=$(MINOR_VERSION) \
|
||||
-DSOGO_PATCH_VERSION=$(SUBMINOR_VERSION) \
|
||||
-DSOGO_LIBDIR="@\"$(SOGO_LIBDIR)\""
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-D_GNU_SOURCE -I../SOPE/ -I../SoObjects/
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
|
||||
-L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/ -lGDLContentStore \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ -lNGCards \
|
||||
-lEOControl -lNGStreams -lNGMime -lNGExtensions -lNGObjWeb -lWEExtensions
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPI : NSObject
|
||||
- (NSArray *) methodAllowed;
|
||||
- (BOOL) needAuth;
|
||||
- (NSArray *) paramNeeded;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
|
||||
@end
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
|
||||
@implementation SOGoAPI
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *) methodAllowed
|
||||
{
|
||||
NSArray *result;
|
||||
|
||||
result = [NSArray arrayWithObjects:@"GET",nil];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray *) paramNeeded
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
@"API not defined", @"error",
|
||||
nil];
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPI */
|
||||
Whitespace-only changes.
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
@class NSMutableDictionary;
|
||||
@class NSURL;
|
||||
@class NSNumber;
|
||||
|
||||
static volatile BOOL apiShouldTerminate = NO;
|
||||
|
||||
@interface SOGoAPIDispatcher : NSObject
|
||||
{
|
||||
|
||||
id context;
|
||||
BOOL debugOn;
|
||||
}
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext;
|
||||
|
||||
@end
|
||||
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoAPIDispatcher.h"
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOCoreApplication.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoOpenIdSession.h>
|
||||
|
||||
|
||||
void handle_api_terminate(int signum)
|
||||
{
|
||||
NSLog(@"Forcing termination of API loop.");
|
||||
apiShouldTerminate = YES;
|
||||
[[WOCoreApplication application] terminateAfterTimeInterval: 1];
|
||||
}
|
||||
|
||||
@implementation SOGoAPIDispatcher
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] apiDebugEnabled];
|
||||
apiShouldTerminate = NO;
|
||||
|
||||
signal(SIGTERM, handle_api_terminate);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) _sendAPIErrorResponse: (WOResponse* ) response
|
||||
withMessage: (NSString *) message
|
||||
withStatus: (unsigned int) status
|
||||
{
|
||||
NSDictionary *msg;
|
||||
msg = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
message, @"error",
|
||||
nil];
|
||||
[response setStatus: status];
|
||||
[response setContent: [msg jsonRepresentation]];
|
||||
}
|
||||
|
||||
- (NSString *) _getActionFromUri: (NSString *) _uri
|
||||
{
|
||||
/*
|
||||
_uri always start with /SOGo/SOGoAPI
|
||||
full _uri example /SOGo/SOGoAPI/Action/subaction1?param1¶m2
|
||||
*/
|
||||
|
||||
NSString *uriWithoutParams, *action, *prefix;
|
||||
NSArray *uriSplits;
|
||||
|
||||
prefix = @"/SOGo/SOGoAPI";
|
||||
action = @"";
|
||||
|
||||
uriWithoutParams = [_uri urlWithoutParameters];
|
||||
if(![uriWithoutParams hasPrefix: prefix])
|
||||
{
|
||||
[self errorWithFormat: @"Uri for API request does not start with /SOGo/SOGoAPI: %@", uriWithoutParams];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:[prefix length]];
|
||||
}
|
||||
|
||||
//remove first and last '/'' if needed
|
||||
if([uriWithoutParams hasPrefix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:1];
|
||||
}
|
||||
if([uriWithoutParams hasSuffix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringToIndex:([uriWithoutParams length] -1)];
|
||||
}
|
||||
if([uriWithoutParams length] == 0)
|
||||
{
|
||||
[self warnWithFormat: @"Uri for API request has no action, make Version instead: %@", uriWithoutParams];
|
||||
return @"SOGoAPIVersion";
|
||||
}
|
||||
else
|
||||
{
|
||||
uriSplits = [uriWithoutParams componentsSeparatedByString: @"/"];
|
||||
action = [@"SOGoAPI" stringByAppendingString: [uriSplits objectAtIndex: 0]];
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"API request, action made is %@", action];
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authBasicCheck: (NSString *) auth
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSRange rng;
|
||||
NSString *decodeCred, *domain, *login, *pwd;
|
||||
SOGoUserManager *lm;
|
||||
SOGoPasswordPolicyError perr;
|
||||
int expire, grace;
|
||||
BOOL rc;
|
||||
|
||||
user = nil;
|
||||
|
||||
decodeCred = [[auth substringFromIndex:5] stringByTrimmingLeadWhiteSpaces];
|
||||
decodeCred = [decodeCred stringByDecodingBase64];
|
||||
|
||||
rng = [decodeCred rangeOfString:@":"];
|
||||
login = [decodeCred substringToIndex:rng.location];
|
||||
pwd = [decodeCred substringFromIndex:(rng.location + rng.length)];
|
||||
|
||||
domain = nil;
|
||||
perr = PolicyNoError;
|
||||
rc = ([[SOGoUserManager sharedUserManager]
|
||||
checkLogin: [login stringByReplacingString: @"%40"
|
||||
withString: @"@"]
|
||||
password: pwd
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace
|
||||
additionalInfo: nil]
|
||||
&& perr == PolicyNoError);
|
||||
|
||||
if(rc)
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authOpenId: (NSString *) auth withDomain: (NSString *) domain
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSString *token, *login;
|
||||
SOGoOpenIdSession *openIdSession;
|
||||
SOGoUserManager *lm;
|
||||
|
||||
user = nil;
|
||||
token = [[auth substringFromIndex:6] stringByTrimmingLeadWhiteSpaces];
|
||||
|
||||
openIdSession = [SOGoOpenIdSession OpenIdSession: domain];
|
||||
if(![openIdSession sessionIsOk])
|
||||
{
|
||||
[self errorWithFormat: @"API - OpenId server not found or has unexpected behavior, contact your admin."];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[openIdSession setAccessToken: token];
|
||||
login = [openIdSession login: @""];
|
||||
|
||||
if(login && ![login isEqualToString: @"anonymous"])
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
id activeUser;
|
||||
NSString *method, *action, *error;
|
||||
NSDictionary *form;
|
||||
NSArray *paramNeeded;
|
||||
NSMutableDictionary *paramInjected, *ret;
|
||||
NSBundle *bundle;
|
||||
id classAction;
|
||||
Class clazz;
|
||||
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
ASSIGN(context, theContext);
|
||||
|
||||
//Get the api action, check it
|
||||
action = [self _getActionFromUri: [theRequest uri]];
|
||||
if(!action)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No actions found for request to API: %@", [theRequest uri]];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//Get the class for this action, check it
|
||||
bundle = [NSBundle bundleForClass: NSClassFromString(@"SOGoAPIProduct")];
|
||||
clazz = [bundle classNamed: action];
|
||||
if(!clazz)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No backend API found for action: %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//try to instantiate the class
|
||||
NS_DURING
|
||||
{
|
||||
classAction = [[clazz alloc] init];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Can't alloc and init class: %@", classAction];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
//Check method
|
||||
method = [theRequest method];
|
||||
if(![[classAction methodAllowed] containsObject: method])
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Method %@ not allowed for action %@", method, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
paramInjected = [NSMutableDictionary dictionary];
|
||||
//Check parameters
|
||||
if((paramNeeded = [classAction paramNeeded]) && [paramNeeded count] >= 1)
|
||||
{
|
||||
NSDictionary* formAndQuery = [theRequest formValues];
|
||||
for(NSString *param in paramNeeded)
|
||||
{
|
||||
id value;
|
||||
if((value = [formAndQuery objectForKey: param]))
|
||||
{
|
||||
NSString* trueValue;
|
||||
if ([value isKindOfClass: [NSArray class]])
|
||||
trueValue = [value lastObject];
|
||||
else
|
||||
trueValue = value;
|
||||
[paramInjected setObject: trueValue forKey: param];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Missing param %@ for action %@", param, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if([classAction needAuth])
|
||||
{
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"Check auth for action %@", action];
|
||||
//check auth
|
||||
NSString *auth = [theRequest headerForKey: @"authorization"];
|
||||
if(auth)
|
||||
{
|
||||
NSDictionary* user;
|
||||
if([[auth lowercaseString] hasPrefix: @"basic"])
|
||||
{
|
||||
//basic auth
|
||||
user = [self _authBasicCheck: auth];
|
||||
}
|
||||
else if([[auth lowercaseString] hasPrefix: @"bearer"])
|
||||
{
|
||||
//openid auth, we may need to know the user-domain to know which openid server to fetch
|
||||
NSString *domain = [theRequest headerForKey: @"user-domain"];
|
||||
user = [self _authOpenId: auth withDomain: domain];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Authorization method incorrect: %@ for action %@", auth, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//add current user in paramInjected
|
||||
if(user){
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"User authenticated %@", user];
|
||||
[paramInjected setObject: user forKey: @"user"];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"User wrong login or not found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No authorization header found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
//Execute action
|
||||
NS_DURING
|
||||
{
|
||||
ret = [classAction action: context withParam: paramInjected];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Internal error during: %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
|
||||
//Make the response
|
||||
[theResponse setContent: [ret jsonRepresentation]];
|
||||
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@interface SOGoAPIProduct : NSObject
|
||||
@end
|
||||
|
||||
@implementation SOGoAPIProduct
|
||||
@end /* SOGoAPIProduct */
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIUserFolder : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIUserFolder.h>
|
||||
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
|
||||
@implementation SOGoAPIUserFolder
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
|
||||
{
|
||||
"calendar":[
|
||||
{
|
||||
"name":"DidyShared",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/12509-67F67D00-1-3105AF40"
|
||||
},
|
||||
{
|
||||
"name":"LocalDidy",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/1BC38-67B60000-1-6E4B6880"
|
||||
},
|
||||
{
|
||||
"name":"Personal Calendar",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/personal"
|
||||
}
|
||||
],
|
||||
"username":"sogo-tests1@example.org",
|
||||
"contact":[
|
||||
{
|
||||
"name":"Personal Address Book",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Contacts/personal"
|
||||
}
|
||||
]
|
||||
}
|
||||
**/
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
NSArray *folders;
|
||||
NSMutableArray *cardavLinks, *caldavLinks;
|
||||
NSString *serverUrl, *basePath, *c_uid, *url;
|
||||
GCSFolderManager *fm;
|
||||
GCSFolder *folder;
|
||||
|
||||
int max, i;
|
||||
|
||||
//Should be a user
|
||||
c_uid = [[[param objectForKey: @"user"] objectForKey: @"emails"] objectAtIndex: 0];
|
||||
|
||||
//fetch folders
|
||||
fm = [GCSFolderManager defaultFolderManager];
|
||||
basePath = [NSString stringWithFormat: @"/Users/%@", c_uid];
|
||||
folders = [fm listSubFoldersAndNamesAtPath: basePath recursive: YES];
|
||||
|
||||
//Generate dav link
|
||||
max = [folders count];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
|
||||
cardavLinks = [NSMutableArray array];
|
||||
caldavLinks = [NSMutableArray array];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
NSMutableDictionary *folderRet;
|
||||
folderRet = [NSMutableDictionary dictionary];
|
||||
folder = [folders objectAtIndex: i];
|
||||
url = [NSString stringWithFormat: @"%@/SOGo/dav/%@/%@", serverUrl, c_uid, [folder objectForKey: @"path"]];
|
||||
[folderRet setObject: url forKey: @"url"];
|
||||
[folderRet setObject: [folder objectForKey: @"name"] forKey: @"name"];
|
||||
if([url rangeOfString:@"/Calendar/"].location == NSNotFound)
|
||||
{
|
||||
//Contacts
|
||||
[cardavLinks addObject: folderRet];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Calendar
|
||||
[caldavLinks addObject: folderRet];
|
||||
}
|
||||
}
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
c_uid, @"username",
|
||||
cardavLinks, @"contact",
|
||||
caldavLinks, @"calendar",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIVersion : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIVersion.h>
|
||||
|
||||
|
||||
@implementation SOGoAPIVersion
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:SOGO_MAJOR_VERSION], @"major",
|
||||
[NSNumber numberWithInt:SOGO_MINOR_VERSION], @"minor",
|
||||
[NSNumber numberWithInt:SOGO_PATCH_VERSION], @"patch",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -1,34 +0,0 @@
|
||||
include ../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../Version
|
||||
|
||||
NEEDS_GUI=no
|
||||
BUNDLE_EXTENSION = .SOGo
|
||||
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
|
||||
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
|
||||
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
|
||||
|
||||
# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-I.. \
|
||||
-I../.. \
|
||||
-I../../SOPE
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib \
|
||||
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
-lSOGo \
|
||||
-lGDLContentStore \
|
||||
-lGDLAccess \
|
||||
-lNGObjWeb \
|
||||
-lNGCards -lNGMime -lNGLdap \
|
||||
-lNGStreams -lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC -lSBJson
|
||||
|
||||
ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
requires = ( MAIN, Appointments, Contacts, Mailer );
|
||||
|
||||
publicResources = ();
|
||||
|
||||
factories = {};
|
||||
|
||||
classes = {
|
||||
SOGoAPI = {
|
||||
protectedBy = "<public>";
|
||||
defaultRoles = {
|
||||
"View" = ( "Authenticated", "PublicUser" );
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
categories = {
|
||||
SOGoAPI = {
|
||||
slots = {
|
||||
};
|
||||
methods = {
|
||||
Version = {
|
||||
protectedBy = "View";
|
||||
pageName = "SOGoAPI";
|
||||
actionName = "sogoVersion";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -34,7 +34,7 @@ ActiveSync_RESOURCE_FILES += \
|
||||
ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/
|
||||
ADDITIONAL_INCLUDE_DIRS += $(shell pkg-config --cflags libwbxml2)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/
|
||||
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
ifeq ($(HAS_LIBRARY_ssl),yes)
|
||||
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
|
||||
BUNDLE_LIBS += -lcrypto
|
||||
endif
|
||||
# compilation settings
|
||||
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define __NGDOMELEMENTACTIVESYNC_H__
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
static NSArray *asElementArray = nil;
|
||||
static NSArray *considerAsSameArray = nil;
|
||||
|
||||
@implementation NGDOMElement (ActiveSync)
|
||||
|
||||
@@ -102,44 +101,7 @@ static NSArray *considerAsSameArray = nil;
|
||||
int i, count;
|
||||
|
||||
if (!asElementArray)
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", @"Add", @"Delete", nil];
|
||||
|
||||
// FIXME
|
||||
/* if the client sends
|
||||
<attachments>
|
||||
<add>
|
||||
...
|
||||
</add>
|
||||
<add>
|
||||
...
|
||||
</add>
|
||||
</attachments>
|
||||
|
||||
the result is a NSarray i.e. {add1; add2; ...}
|
||||
|
||||
if the client sends
|
||||
|
||||
<attachments>
|
||||
<add>
|
||||
...
|
||||
</add>
|
||||
<add>
|
||||
...
|
||||
</add>
|
||||
<delete>
|
||||
...
|
||||
</delete>
|
||||
<delete>
|
||||
...
|
||||
</delete>
|
||||
</attachments>
|
||||
|
||||
|
||||
the result is a NSDictionary ie. Add = { }; Delete = { }; the dictionary would contain only one entry for add
|
||||
*/
|
||||
if (!considerAsSameArray)
|
||||
considerAsSameArray = [[NSArray alloc] initWithObjects: @"Add", @"Delete", nil];
|
||||
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
|
||||
|
||||
data = [NSMutableDictionary dictionary];
|
||||
|
||||
@@ -189,7 +151,7 @@ the result is a NSDictionary ie. Add = { }; Delete = { }; the dictionary would c
|
||||
if (!innerTag)
|
||||
innerTag = [innerElement tagName];
|
||||
|
||||
if ([innerTag isEqualToString: [innerElement tagName]] || [considerAsSameArray containsObject: innerTag])
|
||||
if ([innerTag isEqualToString: [innerElement tagName]])
|
||||
{
|
||||
if ([(id)innerElement isTextNode])
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
|
||||
|
||||
@@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@interface NGMimeMessage (ActiveSync)
|
||||
|
||||
- (NSArray *) allBareRecipients;
|
||||
- (NSArray *) allRecipients;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Inverse inc.
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NGMimeMessage+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGMail/NGMailAddress.h>
|
||||
#import <NGMail/NGMailAddressParser.h>
|
||||
@@ -40,45 +42,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (NSArray *) allRecipients
|
||||
{
|
||||
NSEnumerator *enumerator, *addressList;
|
||||
NSMutableArray *recipients;
|
||||
NGMailAddressParser *parser;
|
||||
NSEnumerator *addressList;
|
||||
NSMutableArray *allRecipients;
|
||||
NGMailAddress *address;
|
||||
NSEnumerator *recipients;
|
||||
NSString *s;
|
||||
NSString *fieldNames[] = {@"to", @"cc", @"bcc"};
|
||||
unsigned int count;
|
||||
|
||||
allRecipients = [NSMutableArray arrayWithCapacity: 16];
|
||||
recipients = [NSMutableArray array];
|
||||
|
||||
for (count = 0; count < 3; count++)
|
||||
enumerator = [[self headersForKey: @"to"] objectEnumerator];
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
recipients = [[self headersForKey: fieldNames[count]] objectEnumerator];
|
||||
while ((s = [recipients nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
while ((address = [addressList nextObject]))
|
||||
[allRecipients addObject: [address address]];
|
||||
}
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
|
||||
return allRecipients;
|
||||
enumerator = [[self headersForKey: @"cc"] objectEnumerator];
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
|
||||
return recipients;
|
||||
}
|
||||
|
||||
- (NSArray *) allBareRecipients
|
||||
{
|
||||
NSMutableArray *bareRecipients;
|
||||
NSEnumerator *allRecipients;
|
||||
NSString *recipient;
|
||||
|
||||
bareRecipients = [NSMutableArray array];
|
||||
|
||||
allRecipients = [[self allRecipients] objectEnumerator];
|
||||
while ((recipient = [allRecipients nextObject]))
|
||||
[bareRecipients addObject: [recipient pureEMailAddress]];
|
||||
|
||||
return bareRecipients;
|
||||
}
|
||||
|
||||
@end
|
||||
+66
-325
@@ -29,12 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#import "NGVCard+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <NGCards/CardElement.h>
|
||||
|
||||
#import <Contacts/NGVCard+SOGo.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
@@ -42,50 +45,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
@implementation NGVCard (ActiveSync)
|
||||
|
||||
//
|
||||
// This function is called for each elements which can be ghosted according to specs.
|
||||
// https://msdn.microsoft.com/en-us/library/gg650908%28v=exchg.80%29.aspx
|
||||
//
|
||||
- (BOOL) _isGhosted: (NSString *) element
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSArray *supportedElements;
|
||||
|
||||
supportedElements = [context objectForKey: @"SupportedElements"];
|
||||
|
||||
// If the client does not include a Supported element in the initial Sync command request for
|
||||
// a folder, then all of the elements that can be ghosted are considered not ghosted.
|
||||
if (!supportedElements)
|
||||
return NO;
|
||||
|
||||
// If the client includes an empty Supported element in the initial Sync command request for
|
||||
// a folder, then all elements that can be ghosted are considered ghosted.
|
||||
if (![supportedElements count])
|
||||
return YES;
|
||||
|
||||
// If the client includes a Supported element that contains child elements in the initial
|
||||
// Sync command request for a folder, then each child element of that Supported element is
|
||||
// considered not ghosted. All elements that can be ghosted that are not included as child
|
||||
// elements of the Supported element are considered ghosted.
|
||||
if (!([supportedElements indexOfObject: element] == NSNotFound))
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *emails, *addresses, *categories, *elements;
|
||||
NSMutableArray *other_addresses;
|
||||
CardElement *n, *homeAdr, *workAdr, *otherAdr;
|
||||
NSMutableString *s, *a;
|
||||
CardElement *n, *homeAdr, *workAdr;
|
||||
NSMutableString *s;
|
||||
NSString *url;
|
||||
id o;
|
||||
|
||||
@@ -96,22 +62,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
|
||||
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
|
||||
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[s appendFormat: @"<MiddleName xmlns=\"Contacts:\">%@</MiddleName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<Title xmlns=\"Contacts:\">%@</Title>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<Suffix xmlns=\"Contacts:\">%@</Suffix>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self fn]))
|
||||
[s appendFormat: @"<FileAs xmlns=\"Contacts:\">%@</FileAs>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [self workCompany]))
|
||||
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
@@ -151,7 +105,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self preferredEMail]))
|
||||
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
|
||||
|
||||
|
||||
// Secondary email addresses (2 and 3)
|
||||
@@ -161,7 +115,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
o = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
|
||||
|
||||
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, [o activeSyncRepresentationInContext: context], i+2];
|
||||
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, o, i+2];
|
||||
|
||||
if (i == 1)
|
||||
break;
|
||||
@@ -191,22 +145,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ([addresses count])
|
||||
{
|
||||
homeAdr = [addresses objectAtIndex: 0];
|
||||
a = [NSMutableString string];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[a appendString: [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
|
||||
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", a];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
|
||||
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
@@ -222,15 +170,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ([addresses count])
|
||||
{
|
||||
workAdr = [addresses objectAtIndex: 0];
|
||||
a = [NSMutableString string];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[a appendString: [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
|
||||
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", a];
|
||||
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
|
||||
@@ -245,57 +187,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
// Other Address
|
||||
|
||||
other_addresses = [[self childrenWithTag: @"adr"] mutableCopy];
|
||||
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]];
|
||||
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]];
|
||||
|
||||
if ([other_addresses count])
|
||||
{
|
||||
otherAdr = [other_addresses objectAtIndex: 0];
|
||||
a = [NSMutableString string];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[a appendString: [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
|
||||
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
[s appendFormat: @"<OtherStreet xmlns=\"Contacts:\">%@</OtherStreet>", a];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<OtherCity xmlns=\"Contacts:\">%@</OtherCity>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<OtherState xmlns=\"Contacts:\">%@</OtherState>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 5 forKey: @""]))
|
||||
[s appendFormat: @"<OtherPostalCode xmlns=\"Contacts:\">%@</OtherPostalCode>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [otherAdr flattenedValueAtIndex: 6 forKey: @""]))
|
||||
[s appendFormat: @"<OtherCountry xmlns=\"Contacts:\">%@</OtherCountry>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Other, less important fields
|
||||
if ((o = [self birthday]))
|
||||
{
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>",
|
||||
[[o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: -12 minutes: 0
|
||||
seconds: 0]
|
||||
activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self note]))
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
@@ -313,11 +215,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
CardElement *element;
|
||||
NSMutableArray *addressLines, *other_addresses;
|
||||
id o, l, m, f, p, s;
|
||||
|
||||
l = m = f = p = s = nil;
|
||||
|
||||
id o;
|
||||
|
||||
// Contact's note
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setNote: o];
|
||||
@@ -325,20 +224,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
else
|
||||
[[self children] removeObjectsInArray: [self childrenWithTag: @"Categories"]];
|
||||
|
||||
// Birthday
|
||||
if ((o = [theValues objectForKey: @"Birthday"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
|
||||
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]];
|
||||
}
|
||||
else if (![self _isGhosted: @"Birthday" inContext: context])
|
||||
{
|
||||
[self setBday: @""];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Business address information
|
||||
@@ -350,48 +242,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// BusinessCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"work"];
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessStreet"]) || ![self _isGhosted: @"BusinessStreet" inContext: context])
|
||||
{
|
||||
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
|
||||
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
|
||||
atIndex: 2 forKey: @""];
|
||||
|
||||
// Extended address line. If there are more than 2 address lines we add them to the extended address line.
|
||||
if ([addressLines count] > 1)
|
||||
{
|
||||
[addressLines removeObjectAtIndex: 0];
|
||||
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
|
||||
atIndex: 1 forKey: @""];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessCity"]) || ![self _isGhosted: @"BusinessCity" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessState"]) || ![self _isGhosted: @"BusinessState" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessPostalCode"]) || ![self _isGhosted: @"BusinessPostalCode" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessCountry"]) || ![self _isGhosted: @"BusinessCountry" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
}
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
//
|
||||
// Home address information
|
||||
@@ -403,126 +265,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// HomeCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"home"];
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeStreet"]) || ![self _isGhosted: @"HomeStreet" inContext: context])
|
||||
{
|
||||
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
|
||||
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
|
||||
atIndex: 2 forKey: @""];
|
||||
|
||||
// Extended address line. If there are more then 2 address lines we add them to the extended address line.
|
||||
if ([addressLines count] > 1)
|
||||
{
|
||||
[addressLines removeObjectAtIndex: 0];
|
||||
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
|
||||
atIndex: 1 forKey: @""];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeCity"]) || ![self _isGhosted: @"HomeCity" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeState"]) || ![self _isGhosted: @"HomeState" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomePostalCode"]) || ![self _isGhosted: @"HomePostalCode" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeCountry"]) || ![self _isGhosted: @"HomeCountry" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
}
|
||||
|
||||
// OtherCountry
|
||||
//
|
||||
|
||||
other_addresses = [[self childrenWithTag: @"adr"] mutableCopy];
|
||||
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]];
|
||||
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]];
|
||||
|
||||
if ([other_addresses count])
|
||||
element = [other_addresses objectAtIndex: 0];
|
||||
else
|
||||
{
|
||||
element = [CardElement elementWithTag: @"adr"];
|
||||
[self addChild: element];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"OtherStreet"]) || ![self _isGhosted: @"OtherStreet" inContext: context])
|
||||
{
|
||||
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
|
||||
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
|
||||
atIndex: 2 forKey: @""];
|
||||
|
||||
// Extended address line. If there are more then 2 address lines we add them to the extended address line.
|
||||
if ([addressLines count] > 1)
|
||||
{
|
||||
[addressLines removeObjectAtIndex: 0];
|
||||
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
|
||||
atIndex: 1 forKey: @""];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"OtherCity"]) || ![self _isGhosted: @"OtherCity" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"OtherCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"OtherState"]) || ![self _isGhosted: @"OtherState" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"OtherState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"OtherPostalCode"]) || ![self _isGhosted: @"OtherPostalCode" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"OtherPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"OtherCountry"]) || ![self _isGhosted: @"OtherCountry" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"OtherCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
}
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
// Company's name
|
||||
if ((o = [theValues objectForKey: @"CompanyName"]))
|
||||
[self setOrg: o units: nil];
|
||||
else if (![self _isGhosted: @"CompanyName" inContext: context])
|
||||
[self setOrg: @"" units: nil];
|
||||
|
||||
// Department
|
||||
if ((o = [theValues objectForKey: @"Department"]))
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
|
||||
else if (![self _isGhosted: @"Department" inContext: context])
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:@"",nil]];
|
||||
|
||||
// Email addresses
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]) || ![self _isGhosted: @"Email1Address" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"work"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]) || ![self _isGhosted: @"Email2Address" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"home"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
@@ -530,7 +301,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
|
||||
// FIXME: revise this when the GUI revamp is done in SOGo
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]) || ![self _isGhosted: @"Email3Address" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"three"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
@@ -540,75 +311,45 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// MiddleName
|
||||
// Suffix (II)
|
||||
// Title (Mr.)
|
||||
if ((o = [theValues objectForKey: @"FileAs"]) || ![self _isGhosted: @"FileAs" inContext: context])
|
||||
[self setFn: [theValues objectForKey: @"FileAs"]];
|
||||
|
||||
if ((o = [theValues objectForKey: @"LastName"]) || ![self _isGhosted: @"LastName" inContext: context])
|
||||
l = o ? o : @"";
|
||||
|
||||
if ((o = [theValues objectForKey: @"FirstName"]) || ![self _isGhosted: @"FirstName" inContext: context])
|
||||
f = o ? o : @"";
|
||||
|
||||
if ((o = [theValues objectForKey: @"MiddleName"]) || ![self _isGhosted: @"MiddleName" inContext: context])
|
||||
m = o ? o : @"";
|
||||
|
||||
if ((o = [theValues objectForKey: @"Title"]) || ![self _isGhosted: @"Title" inContext: context])
|
||||
p = o ? o : @"";
|
||||
|
||||
if ((o = [theValues objectForKey: @"Suffix"]) || ![self _isGhosted: @"Suffix" inContext: context])
|
||||
s = o ? o : @"";
|
||||
|
||||
[self setNWithFamily: l given: f additional: m prefixes: p suffixes: s];
|
||||
[self setFn: [theValues objectForKey: @"FileAs"]];
|
||||
|
||||
[self setNWithFamily: [theValues objectForKey: @"LastName"]
|
||||
given: [theValues objectForKey: @"FirstName"]
|
||||
additional: nil prefixes: nil suffixes: nil];
|
||||
|
||||
// IM information
|
||||
if ((o = [theValues objectForKey: @"IMAddress"]) || ![self _isGhosted: @"IMAddress" inContext: context])
|
||||
[[self uniqueChildWithTag: @"x-aim"]
|
||||
setSingleValue: [theValues objectForKey: @"IMAddress"]
|
||||
forKey: @""];
|
||||
[[self uniqueChildWithTag: @"x-aim"]
|
||||
setSingleValue: [theValues objectForKey: @"IMAddress"]
|
||||
forKey: @""];
|
||||
|
||||
//
|
||||
// Phone numbrrs
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"BusinessPhoneNumber"]) || ![self _isGhosted: @"BusinessPhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
|
||||
}
|
||||
element = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomePhoneNumber"]) || ![self _isGhosted: @"HomePhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
|
||||
}
|
||||
element = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"MobilePhoneNumber"]) || ![self _isGhosted: @"MobilePhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
|
||||
}
|
||||
element = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessFaxNumber"]) || ![self _isGhosted: @"BusinessFaxNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
|
||||
}
|
||||
element = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"PagerNumber"]) || ![self _isGhosted: @"PagerNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
|
||||
}
|
||||
element = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
|
||||
|
||||
// Job's title
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]) || ![self _isGhosted: @"JobTitle" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]))
|
||||
[self setTitle: o];
|
||||
|
||||
// WebPage (work)
|
||||
if ((o = [theValues objectForKey: @"WebPage"]) || ![self _isGhosted: @"WebPage" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"WebPage"]))
|
||||
[[self elementWithTag: @"url" ofType: @"work"]
|
||||
setSingleValue: o forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"NickName"]) || ![self _isGhosted: @"NickName" inContext: context])
|
||||
if ((o = [theValues objectForKey: @"NickName"]))
|
||||
[self setNickname: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Picture"]))
|
||||
|
||||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#define ONE_DAY 86400
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NSData+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#include <wbxml/wbxml.h>
|
||||
#include <wbxml/wbxml_conv.h>
|
||||
#include <wbxml/wbxml_errors.h>
|
||||
|
||||
#define WBXMLDEBUG 0
|
||||
|
||||
@@ -44,18 +44,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (void) _dumpToFile
|
||||
{
|
||||
BOOL debugOn;
|
||||
NSString *path;
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
||||
|
||||
if (debugOn)
|
||||
{
|
||||
NSString *path;
|
||||
|
||||
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
[self writeToFile: path atomically: YES];
|
||||
[self errorWithFormat: @"Original data written to: %@", path];
|
||||
}
|
||||
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
[self writeToFile: path atomically: YES];
|
||||
NSLog(@"Original data written to: %@", path);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -63,33 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSString *tmp, *s;
|
||||
unichar *buf, *start, c;
|
||||
int len, i, j;
|
||||
|
||||
tmp = [self stringByEncodingBase64] ;
|
||||
|
||||
len = [tmp length];
|
||||
|
||||
start = buf = (unichar *)malloc(len*sizeof(unichar));
|
||||
[tmp getCharacters: buf range: NSMakeRange(0, len)];
|
||||
|
||||
for (i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
c = *buf;
|
||||
|
||||
if (!(c == 0xA))
|
||||
{
|
||||
*(start+j) = c;
|
||||
j++;
|
||||
}
|
||||
|
||||
buf++;
|
||||
}
|
||||
|
||||
s = [[NSString alloc] initWithCharactersNoCopy: start length: j freeWhenDone: YES];
|
||||
|
||||
return AUTORELEASE(s);
|
||||
return [[self stringByEncodingBase64] stringByReplacingString: @"\n" withString: @""];
|
||||
}
|
||||
|
||||
- (NSData *) wbxml2xml
|
||||
@@ -114,7 +81,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self errorWithFormat: @"wbxml2xml failed: %s\n", wbxml_errors_string(ret)];
|
||||
NSLog(@"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret));
|
||||
[self _dumpToFile];
|
||||
return nil;
|
||||
}
|
||||
@@ -147,7 +114,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self logWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
|
||||
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
|
||||
[self _dumpToFile];
|
||||
return nil;
|
||||
}
|
||||
@@ -162,7 +129,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self errorWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
|
||||
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
|
||||
[self _dumpToFile];
|
||||
free(wbxml);
|
||||
wbxml_conv_xml2wbxml_destroy(conv);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define __NSSTRINGACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSCalendarDate;
|
||||
@@ -48,11 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) deviceType;
|
||||
- (NSString *) attachmentName;
|
||||
- (NSString *) command;
|
||||
- (NSString *) collectionid;
|
||||
- (NSString *) itemid;
|
||||
- (BOOL) acceptsMultiPart;
|
||||
- (NSData *) convertHexStringToBytes;
|
||||
- (NSString *) protocolVersion;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
|
||||
#include <SOGo/NSString+Utilities.h>
|
||||
#include <SOGo/NSData+Crypto.h>
|
||||
@@ -62,7 +64,11 @@ static NSArray *easCommandParameters = nil;
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
return [self safeStringByEscapingXMLString: YES];
|
||||
NSString *s;
|
||||
|
||||
s = [self safeString];
|
||||
|
||||
return [s stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
- (int) activeSyncFolderType
|
||||
@@ -121,45 +127,16 @@ static NSArray *easCommandParameters = nil;
|
||||
//
|
||||
- (NSCalendarDate *) calendarDate
|
||||
{
|
||||
NSString *s;
|
||||
id o;
|
||||
|
||||
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
|
||||
// in the default timezone.
|
||||
s = [NSString stringWithFormat: @"%@ GMT", self];
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
|
||||
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
|
||||
|
||||
if (!o)
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
|
||||
|
||||
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (NSString *) protocolVersion
|
||||
{
|
||||
NSMutableArray *components;
|
||||
|
||||
components = [NSMutableArray arrayWithArray: [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"]];
|
||||
|
||||
// We handle BASE64 encoded queryStrings. See http://msdn.microsoft.com/en-us/library/ee160227%28v=exchg.80%29.aspx for details.
|
||||
if ([components count] == 1)
|
||||
{
|
||||
NSData *queryString;
|
||||
const char* qs_bytes;
|
||||
|
||||
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
|
||||
|
||||
if (![queryString length])
|
||||
return nil;
|
||||
|
||||
qs_bytes = (const char*)[queryString bytes];
|
||||
|
||||
return [NSString stringWithFormat:@"%.1f", (float)((uint8_t)qs_bytes[0]/10)];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *) _valueForParameter: (NSString *) theParameter
|
||||
{
|
||||
NSMutableArray *components;
|
||||
@@ -200,11 +177,6 @@ static NSArray *easCommandParameters = nil;
|
||||
|
||||
// Command code, 1 byte, ie.: cmd=
|
||||
cmd_code = qs_bytes[1];
|
||||
|
||||
// Check whether the command code is within the known range.
|
||||
if (cmd_code < 0 || cmd_code > 22)
|
||||
return nil;
|
||||
|
||||
[components addObject: [NSString stringWithFormat: @"cmd=%@", [easCommandCodes objectAtIndex: cmd_code]]];
|
||||
|
||||
// Device ID length and Device ID (variable)
|
||||
@@ -234,7 +206,7 @@ static NSArray *easCommandParameters = nil;
|
||||
|
||||
// parameter_code 7 == Options
|
||||
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
|
||||
if (parameter_code == 7 && ! [parameterValue isEqualToString: @"\000"] )
|
||||
if (parameter_code == 7)
|
||||
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
|
||||
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
|
||||
else
|
||||
@@ -321,43 +293,6 @@ static NSArray *easCommandParameters = nil;
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) itemid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"ITEMID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) collectionid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"COLLECTIONID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (BOOL) acceptsMultiPart
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"OPTIONS="];
|
||||
|
||||
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ to negotiate the fees associated to your user base.
|
||||
|
||||
To contact Microsoft, please visit:
|
||||
|
||||
http://www.microsoft.com/en-us/legal/intellectualproperty/
|
||||
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
|
||||
|
||||
and send an email to iplicreq@microsoft.com
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "SOGoActiveSyncDispatcher.h"
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class WOResponse;
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -27,31 +27,19 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
@class NSMutableDictionary;
|
||||
@class NSURL;
|
||||
@class NSNumber;
|
||||
|
||||
static volatile BOOL easShouldTerminate = NO;
|
||||
|
||||
@interface SOGoActiveSyncDispatcher : NSObject
|
||||
{
|
||||
NSURL *folderTableURL;
|
||||
NSDictionary *imapFolderGUIDS;
|
||||
id context;
|
||||
|
||||
NSNumber *syncRequest;
|
||||
BOOL debugOn;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) globalMetadataForDevice;
|
||||
|
||||
- (id) collectionFromId: (NSString *) theCollectionId
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
@@ -64,6 +52,5 @@ static volatile BOOL easShouldTerminate = NO;
|
||||
|
||||
- (NSURL *) folderTableURL;
|
||||
- (void) ensureFolderTableExists;
|
||||
- (BOOL) easShouldTerminate;
|
||||
|
||||
@end
|
||||
+718
-2669
File diff suppressed because it is too large.
Load diff
@@ -42,9 +42,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
- (NSString *) storeMail: (NSDictionary *) theValues
|
||||
inBuffer: (NSMutableString *) theBuffer
|
||||
inContext: (WOContext *) _context;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+134
-1080
File diff suppressed because it is too large.
Load diff
@@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@interface SOGoSyncCacheObject : NSObject
|
||||
{
|
||||
@public
|
||||
id _uid;
|
||||
id _sequence;
|
||||
}
|
||||
|
||||
@@ -32,17 +32,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
static Class NSNullK;
|
||||
|
||||
@implementation SOGoSyncCacheObject
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
NSNullK = [NSNull class];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
@@ -54,16 +46,16 @@ static Class NSNullK;
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
{
|
||||
id o;
|
||||
|
||||
o = [[self alloc] init];
|
||||
|
||||
[o setUID: [NSNumber numberWithInt: [theUID intValue]]];
|
||||
[o setSequence: ([theSequence isKindOfClass: NSNullK] ? theSequence : [NSNumber numberWithInt: [theSequence intValue]])];
|
||||
|
||||
[o setUID: theUID];
|
||||
[o setSequence: theSequence];
|
||||
|
||||
return [o autorelease];
|
||||
return o;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
@@ -75,7 +67,7 @@ static Class NSNullK;
|
||||
|
||||
- (id) uid
|
||||
{
|
||||
return [_uid description];
|
||||
return _uid;
|
||||
}
|
||||
|
||||
- (void) setUID: (id) theUID
|
||||
@@ -85,7 +77,7 @@ static Class NSNullK;
|
||||
|
||||
- (id) sequence
|
||||
{
|
||||
return ([_sequence isKindOfClass: NSNullK] ? _sequence : [_sequence description]);
|
||||
return _sequence;
|
||||
}
|
||||
|
||||
- (void) setSequence: (id) theSequence
|
||||
@@ -96,7 +88,7 @@ static Class NSNullK;
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
return [self->_uid compare: theSyncCacheObject->_uid];
|
||||
return [[self uid] compare: [theSyncCacheObject uid]];
|
||||
}
|
||||
|
||||
//
|
||||
@@ -105,21 +97,21 @@ static Class NSNullK;
|
||||
//
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
if ([self->_sequence isEqual: [NSNull null]] &&
|
||||
[theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
if ([[self sequence] isEqual: [NSNull null]] &&
|
||||
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
if (![self->_sequence isEqual: [NSNull null]] && [theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedDescending;
|
||||
|
||||
if ([self->_sequence isEqual: [NSNull null]] && ![theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedAscending;
|
||||
|
||||
// Must check this here, to avoid comparing NSNull objects
|
||||
if ([self->_sequence compare: theSyncCacheObject->_sequence] == NSOrderedSame)
|
||||
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
return [self->_sequence compare: theSyncCacheObject->_sequence];
|
||||
return [[self sequence] compare: [theSyncCacheObject sequence]];
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
@@ -128,4 +120,3 @@ static Class NSNullK;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,11 +27,9 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <NGObjWeb/SoObjectWebDAVDispatcher.h>
|
||||
|
||||
#include <NGObjWeb/SoObject+SoDAV.h>
|
||||
|
||||
#include <NGObjWeb/WEClientCapabilities.h>
|
||||
#include <NGObjWeb/WOContext.h>
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
@@ -39,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
|
||||
@interface SoObjectWebDAVDispatcher (ActiveSync)
|
||||
|
||||
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
|
||||
@@ -64,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[response setHeader: @"private" forKey: @"Cache-Control"];
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
|
||||
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
|
||||
[response setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
[response setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib \
|
||||
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
|
||||
-Wl,-rpath,$(GNUSTEP_SYSTEM_LIBRARIES)/sogo
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
-lSOGo \
|
||||
|
||||
@@ -30,38 +30,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "iCalAlarm+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
|
||||
#include "NSDate+ActiveSync.h"
|
||||
|
||||
@implementation iCalAlarm (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSCalendarDate *nextAlarmDate;
|
||||
NSInteger delta;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
nextAlarmDate = [self nextAlarmDate];
|
||||
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
|
||||
|
||||
if ([parent isKindOfClass: [iCalEvent class]])
|
||||
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
|
||||
{
|
||||
NSCalendarDate *nextAlarmDate;
|
||||
NSInteger delta;
|
||||
|
||||
nextAlarmDate = [self nextAlarmDate];
|
||||
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
|
||||
|
||||
// don't send negative reminder - not supported
|
||||
if (delta > 0)
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<ReminderTime xmlns=\"Task:\">%@</ReminderTime>", [nextAlarmDate activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
|
||||
}
|
||||
|
||||
return s;
|
||||
@@ -73,56 +70,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
iCalTrigger *trigger;
|
||||
id o;
|
||||
|
||||
if ((o = [theValues objectForKey: @"Reminder"]))
|
||||
o = [theValues objectForKey: @"Reminder"];
|
||||
|
||||
// Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo
|
||||
if ([o isEqualToString: @"0"])
|
||||
o = @"1";
|
||||
|
||||
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
|
||||
[trigger setValueType: @"DURATION"];
|
||||
[self setTrigger: trigger];
|
||||
[self setAction: @"DISPLAY"];
|
||||
|
||||
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
|
||||
// 1week = -P1W
|
||||
// 2weeks > -PxD
|
||||
// xdays > -PxD
|
||||
// xhours -> -PTxH
|
||||
// xmin -> -PTxM
|
||||
if ([o intValue] == 10080)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
|
||||
else
|
||||
{
|
||||
// Outlook: if reminder is set to 0 minutes before starttime, save it as 1 minute since -> 0 minutes in not accepted by SOGo
|
||||
if ([o isEqualToString: @"0"])
|
||||
o = @"1";
|
||||
|
||||
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
|
||||
[trigger setValueType: @"DURATION"];
|
||||
[self setTrigger: trigger];
|
||||
if (![[self action] length])
|
||||
[self setAction: @"DISPLAY"];
|
||||
|
||||
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
|
||||
// 1week = -P1W
|
||||
// 2weeks > -PxD
|
||||
// xdays > -PxD
|
||||
// xhours -> -PTxH
|
||||
// xmin -> -PTxM
|
||||
if ([o intValue] == 10080)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
|
||||
if (([o intValue] % 1440) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 1440) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
|
||||
if (([o intValue] % 60) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 60) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
|
||||
else
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
|
||||
}
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
|
||||
}
|
||||
}
|
||||
else if ((o = [theValues objectForKey: @"ReminderTime"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
|
||||
[trigger setValueType: @"DATE-TIME"];
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"%@Z", [o iCalFormattedDateTimeString]] forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"ReminderSet"]))
|
||||
{
|
||||
if ([o intValue] == 0)
|
||||
[trigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
|
||||
}
|
||||
|
||||
[self setTrigger: trigger];
|
||||
if (![[self action] length])
|
||||
[self setAction: @"DISPLAY"];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -41,9 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
- (void) changeParticipationStatus: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
component: (id) component;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -30,27 +30,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import "iCalEvent+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
#import <Appointments/iCalRepeatableEntityObject+SOGo.h>
|
||||
#import <Appointments/SOGoAppointmentObject.h>
|
||||
|
||||
#include "iCalAlarm+ActiveSync.h"
|
||||
#include "iCalRecurrenceRule+ActiveSync.h"
|
||||
@@ -63,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (int) _attendeeStatus: (iCalPerson *) attendee
|
||||
{
|
||||
int attendee_status;
|
||||
|
||||
|
||||
attendee_status = 5;
|
||||
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
|
||||
attendee_status = 3;
|
||||
@@ -75,39 +73,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
return attendee_status;
|
||||
}
|
||||
|
||||
//
|
||||
// Possible values are:
|
||||
// 0 Free
|
||||
// 1 Tentative
|
||||
// 2 Busy
|
||||
// 3 Out of Office
|
||||
// 4 Working elsewhere
|
||||
//
|
||||
- (int) _busyStatus: (iCalPerson *) attendee
|
||||
{
|
||||
int attendee_status;
|
||||
|
||||
attendee_status = 2;
|
||||
|
||||
if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
|
||||
attendee_status = 0;
|
||||
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
|
||||
attendee_status = 1;
|
||||
|
||||
return attendee_status;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSArray *attendees, *categories;
|
||||
NSArray *attendees;
|
||||
|
||||
iCalPerson *organizer, *attendee;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
int v, i, meetingStatus;
|
||||
int v;
|
||||
|
||||
NSTimeZone *userTimeZone;
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
@@ -122,13 +97,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else if ([self created])
|
||||
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
|
||||
if ([self startDate])
|
||||
{
|
||||
if ([self isAllDay] && !tz && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
|
||||
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
@@ -141,7 +113,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
|
||||
if ([self endDate])
|
||||
{
|
||||
if ([self isAllDay] && !tz && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
|
||||
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
@@ -151,24 +123,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
if (!tz)
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
|
||||
if (![self recurrenceId])
|
||||
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Organizer and other invitations related properties
|
||||
if ((organizer = [self organizer]))
|
||||
{
|
||||
meetingStatus = 1; // meeting and the user is the meeting organizer.
|
||||
o = [organizer rfc822Email];
|
||||
if (![self recurrenceId] && [o length])
|
||||
if ([o length])
|
||||
{
|
||||
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
|
||||
|
||||
o = [organizer cn];
|
||||
if ([o length])
|
||||
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", o];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,11 +159,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
|
||||
|
||||
attendee = [attendees objectAtIndex: i];
|
||||
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
|
||||
if ([[attendee cn] length])
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
|
||||
|
||||
attendee_status = [self _attendeeStatus: attendee];
|
||||
|
||||
@@ -207,10 +177,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
[s appendString: @"</Attendees>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
meetingStatus = 0; // The event is an appointment, which has no attendees.
|
||||
}
|
||||
|
||||
// This depends on the 'NEEDS-ACTION' parameter.
|
||||
// This will trigger the SendMail command
|
||||
@@ -220,26 +186,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
int attendee_status;
|
||||
|
||||
meetingStatus = 3; // event is a meeting, and the user is not the meeting organizer
|
||||
|
||||
attendee = [self userAsAttendee: [context activeUser]];
|
||||
attendee_status = [self _attendeeStatus: attendee];
|
||||
|
||||
[s appendFormat: @"<ResponseRequested xmlns=\"Calendar:\">%d</ResponseRequested>", 1];
|
||||
[s appendFormat: @"<ResponseType xmlns=\"Calendar:\">%d</ResponseType>", attendee_status];
|
||||
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", 3];
|
||||
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Calendar:\">%d</DisallowNewTimeProposal>", 1];
|
||||
|
||||
// BusyStatus -- http://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
|
||||
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", [self _busyStatus: attendee]];
|
||||
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's a normal event (i.e. with no organizer/attendee) or we are the organizer of an event
|
||||
// invitation, we set the busy status depending on TRANSP.
|
||||
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", (([self isOpaque]) ? 2 : 0)];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", meetingStatus];
|
||||
|
||||
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
|
||||
if ([[self summary] length])
|
||||
@@ -247,12 +204,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Location
|
||||
if ([[self location] length])
|
||||
{
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0)
|
||||
[s appendFormat: @"<Location xmlns=\"AirSyncBase:\"><DisplayName>%@</DisplayName></Location>", [[self location] activeSyncRepresentationInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Importance - NOT SUPPORTED - DO NOT ENABLE
|
||||
//o = [self priority];
|
||||
@@ -265,142 +217,49 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
|
||||
|
||||
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
|
||||
if (![self recurrenceId] && [[self uid] length])
|
||||
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [[self uid] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Comment
|
||||
o = [self comment];
|
||||
//if (![self recurrenceId] && [o length])
|
||||
if ([o length])
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", (int)[o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
if ([[self uid] length])
|
||||
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
v = 3;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Calendar:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Calendar:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
|
||||
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
|
||||
// TODO: improve this to handle more alarm types
|
||||
if ([self hasAlarms])
|
||||
{
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [self firstSupportedAlarm];
|
||||
alarm = [self firstDisplayOrAudioAlarm];
|
||||
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
NSMutableArray *components, *exdates;
|
||||
iCalEvent *current_component;
|
||||
NSString *recurrence_id;
|
||||
|
||||
unsigned int count, max, i;
|
||||
|
||||
components = [NSMutableArray arrayWithArray: [[self parent] events]];
|
||||
max = [components count];
|
||||
|
||||
if (max > 1 || [self hasExceptionDates])
|
||||
{
|
||||
exdates = [NSMutableArray arrayWithArray: [self exceptionDates]];
|
||||
|
||||
[s appendString: @"<Exceptions xmlns=\"Calendar:\">"];
|
||||
|
||||
for (count = 1; count < max; count++)
|
||||
{
|
||||
current_component = [components objectAtIndex: count] ;
|
||||
|
||||
if ([self isAllDay])
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@",
|
||||
[[[current_component recurrenceId] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: -[userTimeZone secondsFromGMTForDate:
|
||||
[current_component recurrenceId]]]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@", [[current_component recurrenceId]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
[s appendString: @"<Exception>"];
|
||||
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
|
||||
[s appendFormat: @"%@", [current_component activeSyncRepresentationInContext: context]];
|
||||
[s appendString: @"</Exception>"];
|
||||
}
|
||||
|
||||
for (i = 0; i < [exdates count]; i++)
|
||||
{
|
||||
[s appendString: @"<Exception>"];
|
||||
[s appendString: @"<Exception_Deleted>1</Exception_Deleted>"];
|
||||
|
||||
if ([self isAllDay])
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@",
|
||||
[[[[exdates objectAtIndex: i] asCalendarDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: -[userTimeZone secondsFromGMTForDate:
|
||||
[[exdates objectAtIndex: i] asCalendarDate]]]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@", [[[exdates objectAtIndex: i] asCalendarDate]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
|
||||
[s appendString: @"</Exception>"];
|
||||
}
|
||||
|
||||
[s appendString: @"</Exceptions>"];
|
||||
}
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
if (![self recurrenceId])
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
// Comment
|
||||
o = [self comment];
|
||||
if ([o length])
|
||||
{
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -446,21 +305,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalDateTime *start, *end; //, *oldstart;
|
||||
NSCalendarDate *oldstart;
|
||||
iCalDateTime *start, *end;
|
||||
NSTimeZone *userTimeZone;
|
||||
iCalTimeZone *tz;
|
||||
iCalAlarm *alarm;
|
||||
id o;
|
||||
int deltasecs;
|
||||
|
||||
NSInteger tzOffset;
|
||||
BOOL isAllDay;
|
||||
|
||||
NSMutableArray *occurences;
|
||||
|
||||
occurences = [NSMutableArray arrayWithArray: [[self parent] events]];
|
||||
|
||||
if ((o = [theValues objectForKey: ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0) ? @"ClientUid" : @"UID"]))
|
||||
|
||||
if ((o = [theValues objectForKey: @"UID"]))
|
||||
[self setUid: o];
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
@@ -472,27 +325,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
isAllDay = YES;
|
||||
}
|
||||
else if ([occurences count] && !([theValues objectForKey: @"AllDayEvent"]))
|
||||
{
|
||||
// If the occurence has no AllDay tag use it from master.
|
||||
isAllDay = [[occurences objectAtIndex: 0] isAllDay];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- free, 1- tentative, 2- busy and 3- out of office
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"BusyStatus"]))
|
||||
{
|
||||
if ([o boolValue])
|
||||
[self setTransparency: @"OPAQUE"];
|
||||
else
|
||||
[self setTransparency: @"TRANSPARENT"];
|
||||
[o intValue];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- normal, 1- personal, 2- private and 3-confidential
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"Sensitivity"]))
|
||||
if ((o = [theValues objectForKey: @"Sensitivy"]))
|
||||
{
|
||||
switch ([o intValue])
|
||||
{
|
||||
@@ -508,65 +353,46 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setAccessClass: @"PUBLIC"];
|
||||
}
|
||||
}
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
|
||||
|
||||
// We ignore TimeZone sent by mobile devices for now.
|
||||
// Some Windows devices don't send during event updates.
|
||||
//if ((o = [theValues objectForKey: @"TimeZone"]))
|
||||
// {
|
||||
// }
|
||||
//else
|
||||
{
|
||||
// We haven't received a timezone, let's use the user's timezone
|
||||
// specified in SOGo for now.
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
}
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
//}
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0 && (o = [theValues objectForKey: @"Location"]))
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Location"]))
|
||||
[self setLocation: o];
|
||||
else if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0 && (o = [theValues objectForKey: @"Location"]) && [o isKindOfClass: [NSDictionary class]])
|
||||
[self setLocation: [o objectForKey: @"DisplayName"]];
|
||||
|
||||
deltasecs = 0;
|
||||
start = nil;
|
||||
|
||||
if ((o = [theValues objectForKey: @"StartTime"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
oldstart = [start dateTime];
|
||||
[start setTimeZone: tz];
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[start setDate: o];
|
||||
[start setTimeZone: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[start setDateTime: o];
|
||||
}
|
||||
|
||||
// Calculate delta if start date has been changed.
|
||||
if (oldstart)
|
||||
deltasecs = [[start dateTime ] timeIntervalSinceDate: oldstart] * -1;
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"EndTime"]))
|
||||
@@ -577,28 +403,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[end setDate: o];
|
||||
[end setTimeZone: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[end setDateTime: o];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
|
||||
//
|
||||
// If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite.
|
||||
//
|
||||
if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame)
|
||||
{
|
||||
// Ignore the alarm for now
|
||||
}
|
||||
else if ((o = [theValues objectForKey: @"Reminder"]))
|
||||
{
|
||||
if ([self hasAlarms])
|
||||
alarm = [[self firstSupportedAlarm] mutableCopy];
|
||||
else
|
||||
alarm = [[iCalAlarm alloc] init];
|
||||
|
||||
// NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified
|
||||
// although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders)
|
||||
//
|
||||
// http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088
|
||||
//
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [[iCalAlarm alloc] init];
|
||||
[alarm takeActiveSyncValues: theValues inContext: context];
|
||||
|
||||
[self removeAllAlarms];
|
||||
@@ -612,7 +450,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
// Recurrence
|
||||
if ((o = [theValues objectForKey: @"Recurrence"]) && [o isKindOfClass: [NSDictionary class]])
|
||||
if ((o = [theValues objectForKey: @"Recurrence"]))
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
@@ -621,177 +459,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
RELEASE(rule);
|
||||
|
||||
[rule takeActiveSyncValues: o inContext: context];
|
||||
|
||||
// Exceptions
|
||||
if ((o = [theValues objectForKey: @"Exceptions"]) && [o isKindOfClass: [NSArray class]])
|
||||
{
|
||||
NSCalendarDate *recurrenceId, *adjustedRecurrenceId, *currentId;
|
||||
NSMutableArray *exdates, *exceptionstouched;
|
||||
iCalEvent *currentOccurence;
|
||||
NSDictionary *exception;
|
||||
|
||||
unsigned int i, count, max;
|
||||
|
||||
[self removeAllExceptionDates];
|
||||
|
||||
exdates = [NSMutableArray array];
|
||||
exceptionstouched = [NSMutableArray array];
|
||||
|
||||
for (i = 0; i < [o count]; i++)
|
||||
{
|
||||
exception = [o objectAtIndex: i];
|
||||
|
||||
if (![[exception objectForKey: @"Exception_Deleted"] intValue])
|
||||
{
|
||||
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
|
||||
|
||||
if (isAllDay)
|
||||
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
|
||||
|
||||
// When moving the calendar entry (i.e. changing the startDate) iOS and Android sometimes send a value for
|
||||
// Exception_StartTime which is not what we expect.
|
||||
// With this we make sure the recurrenceId is always correct.
|
||||
//
|
||||
// iOS problem - If the master is a no-allday-event but the exception is, an invalid Exception_StartTime is in the request.
|
||||
// e.g. it sends 20150409T040000Z instead of 20150409T060000Z;
|
||||
// This might be a special case since iPhone doesn't allow an allday-exception on a non-allday-event.
|
||||
if (!([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay] minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
|
||||
recurrenceId = [recurrenceId hour:[[start dateTime] hourOfDay] minute:[[start dateTime] minuteOfHour]];
|
||||
|
||||
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
|
||||
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
|
||||
adjustedRecurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0 seconds: deltasecs];
|
||||
|
||||
// search for an existing occurence and update it
|
||||
max = [occurences count];
|
||||
currentOccurence = nil;
|
||||
count = 1;
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count] ;
|
||||
currentId = [currentOccurence recurrenceId];
|
||||
|
||||
if ([currentId compare: adjustedRecurrenceId] == NSOrderedSame)
|
||||
{
|
||||
[exceptionstouched addObject: adjustedRecurrenceId];
|
||||
[currentOccurence takeActiveSyncValues: exception inContext: context];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
currentOccurence = nil;
|
||||
}
|
||||
|
||||
// Create a new occurence if we found none to update.
|
||||
if (!currentOccurence)
|
||||
{
|
||||
iCalDateTime *recid;
|
||||
|
||||
currentOccurence = [self mutableCopy];
|
||||
[currentOccurence removeAllRecurrenceRules];
|
||||
[currentOccurence removeAllExceptionRules];
|
||||
[currentOccurence removeAllExceptionDates];
|
||||
|
||||
[[self parent] addToEvents: currentOccurence];
|
||||
[currentOccurence takeActiveSyncValues: exception inContext: context];
|
||||
|
||||
recid = (iCalDateTime *)[currentOccurence uniqueChildWithTag: @"recurrence-id"];
|
||||
if (isAllDay)
|
||||
[recid setDate: adjustedRecurrenceId];
|
||||
else
|
||||
[recid setDateTime: adjustedRecurrenceId];
|
||||
|
||||
[exceptionstouched addObject: [recid dateTime]];
|
||||
}
|
||||
}
|
||||
else if ([[exception objectForKey: @"Exception_Deleted"] intValue])
|
||||
{
|
||||
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
|
||||
|
||||
if (isAllDay)
|
||||
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0
|
||||
days: 0 hours: 0 minutes: 0
|
||||
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
|
||||
|
||||
// We add only valid exception dates.
|
||||
if ([self doesOccurOnDate: recurrenceId] &&
|
||||
([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay]
|
||||
minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
|
||||
{
|
||||
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
|
||||
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
|
||||
[exdates addObject: [recurrenceId dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: deltasecs]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update exception dates in master event.
|
||||
max = [exdates count];
|
||||
if (max > 0)
|
||||
{
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
if (([exceptionstouched indexOfObject: [exdates objectAtIndex: count]] == NSNotFound))
|
||||
[self addToExceptionDates: [exdates objectAtIndex: count]];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all exceptions included in the request.
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count] ;
|
||||
currentId = [currentOccurence recurrenceId];
|
||||
|
||||
// Delete all occurences which are not touched (modified/added).
|
||||
if (([exceptionstouched indexOfObject: currentId] == NSNotFound))
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else if ([self isRecurrent])
|
||||
{
|
||||
// We have no exceptions in request but there is a recurrence rule.
|
||||
// Remove all excpetions and exception dates.
|
||||
iCalEvent *currentOccurence;
|
||||
unsigned int count, max;
|
||||
|
||||
[self removeAllExceptionDates];
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count];
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([self isRecurrent])
|
||||
{
|
||||
// We have no recurrence rule in request.
|
||||
// Remove all exceptions, exception dates and recurrence rules.
|
||||
iCalEvent *currentOccurence;
|
||||
unsigned int count, max;
|
||||
|
||||
[self removeAllRecurrenceRules];
|
||||
[self removeAllExceptionRules];
|
||||
[self removeAllExceptionDates];
|
||||
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count];
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Organizer - we don't touch the value unless we're the organizer
|
||||
@@ -799,7 +466,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
|
||||
{
|
||||
iCalPerson *person;
|
||||
|
||||
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: o];
|
||||
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
||||
@@ -807,14 +474,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
|
||||
//
|
||||
// iOS is plain stupid here. It seends event invitations with no Organizer.
|
||||
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
|
||||
// and there's no organizer, we fake one.
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"MeetingStatus"]))
|
||||
{
|
||||
//
|
||||
// iOS is plain stupid here. It seends event invitations with no Organizer.
|
||||
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
|
||||
// and there's no organizer, we fake one.
|
||||
//
|
||||
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
|
||||
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"])
|
||||
{
|
||||
iCalPerson *person;
|
||||
|
||||
@@ -824,29 +491,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
|
||||
//
|
||||
// When MeetingResponse fails Outlook still sends a new calendar entry with MeetingStatus=3.
|
||||
// Use the organizer from the request if the event has no organizer.
|
||||
//
|
||||
if ([o intValue] == 3 && [theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
|
||||
{
|
||||
iCalPerson *person;
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: [theValues objectForKey: @"Organizer_Email"]];
|
||||
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Attendees - we don't touch the values if we're an attendee. This is gonna
|
||||
// be done automatically by the ActiveSync client when invoking MeetingResponse.
|
||||
if (![self userIsAttendee: [context activeUser]])
|
||||
{
|
||||
// Windows phones sens sometimes an empty Attendees tag.
|
||||
// We check it's an array before processing it.
|
||||
if ((o = [theValues objectForKey: @"Attendees"]) && [o isKindOfClass: [NSArray class]])
|
||||
if ((o = [theValues objectForKey: @"Attendees"])&& [o isKindOfClass: [NSArray class]])
|
||||
{
|
||||
NSMutableArray *attendees;
|
||||
NSDictionary *attendee;
|
||||
@@ -861,13 +515,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
|
||||
attendee = [o objectAtIndex: i];
|
||||
|
||||
if ([self isOrganizer: [attendee objectForKey: @"Attendee_Email"]])
|
||||
continue;
|
||||
|
||||
person = [iCalPerson elementWithTag: @"attendee"];
|
||||
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
|
||||
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
|
||||
|
||||
|
||||
status = [[attendee objectForKey: @"Attendee_Status"] intValue];
|
||||
|
||||
switch (status)
|
||||
@@ -884,10 +535,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
case 0:
|
||||
case 5:
|
||||
default:
|
||||
{
|
||||
[person setPartStat: @"NEEDS-ACTION"];
|
||||
[person setRsvp: @"TRUE"];
|
||||
}
|
||||
[person setPartStat: @"NEEDS-ACTION"];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -899,61 +547,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setAttendees: attendees];
|
||||
}
|
||||
}
|
||||
|
||||
[self setLastModified: [NSCalendarDate calendarDate]];
|
||||
}
|
||||
|
||||
- (void) changeParticipationStatus: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
component: (id) component
|
||||
{
|
||||
NSString *status;
|
||||
iCalAlarm *alarm;
|
||||
iCalPerson *attendee;
|
||||
id o;
|
||||
|
||||
|
||||
attendee = [self userAsAttendee: [context activeUser]];
|
||||
status = [attendee partStat];
|
||||
alarm = nil;
|
||||
|
||||
// See: https://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
|
||||
//
|
||||
// 0 == Free
|
||||
// 1 == Tentative
|
||||
// 2 == Busy
|
||||
// 3 == Out of Office
|
||||
// 4 == Working elsehwere
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"BusyStatus"]))
|
||||
{
|
||||
// We translate >= 2 into ACCEPTED
|
||||
if ([o intValue] == 0)
|
||||
status = @"NEEDS-ACTION";
|
||||
else if ([o intValue] >= 2)
|
||||
status = @"ACCEPTED";
|
||||
else
|
||||
status = @"TENTATIVE";
|
||||
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
|
||||
{
|
||||
if ([self hasAlarms])
|
||||
alarm = [[self firstSupportedAlarm] mutableCopy];
|
||||
else
|
||||
alarm = [[iCalAlarm alloc] init];
|
||||
|
||||
[alarm takeActiveSyncValues: theValues inContext: context];
|
||||
|
||||
|
||||
}
|
||||
|
||||
// There's no delegate in EAS
|
||||
[(SOGoAppointmentObject *) component changeParticipationStatus: status
|
||||
withDelegate: nil
|
||||
alarm: alarm];
|
||||
RELEASE(alarm);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -35,42 +35,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
#import "NSDate+ActiveSync.h"
|
||||
|
||||
@implementation iCalRecurrenceRule (ActiveSync)
|
||||
|
||||
- (NSCalendarDate *) _adjustedStartDate
|
||||
{
|
||||
iCalTimeZone *timeZone;
|
||||
|
||||
timeZone = [(iCalDateTime *)[[self parent] firstChildWithTag: @"dtstart"] timeZone];
|
||||
if (timeZone)
|
||||
return [timeZone computedDateForDate: [[self parent] startDate]];
|
||||
else
|
||||
return [[self parent] startDate];
|
||||
}
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSString *t;
|
||||
int type;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
if ([[self parent] isKindOfClass: [iCalToDo class]])
|
||||
t = @"Tasks";
|
||||
else
|
||||
t = @"Calendar";
|
||||
|
||||
[s appendFormat: @"<Recurrence xmlns=\"%@:\">", t];
|
||||
|
||||
[s appendString: @"<Recurrence xmlns=\"Calendar:\">"];
|
||||
|
||||
// 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly
|
||||
type = 0;
|
||||
@@ -82,11 +61,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 1 -> sunday, 2 -> monday, 4 -> tuesday, 8 -> wednesday, 16 -> thursday, 32 -> friday, 64 -> saturday, 127 -> last day of month (montly or yearl recurrences only)
|
||||
if ([[self byDayMask] isWeekDays])
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (2|4|8|16|32)];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (2|4|8|16|32)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceWeekly)
|
||||
@@ -111,11 +90,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// No byDayMask, we take the event's start date to compute the DayOfWeek
|
||||
// 0 == Sunday, 6 == Saturday
|
||||
v = (1 << [[self _adjustedStartDate] dayOfWeek]);
|
||||
v = (1 << [[[self parent] startDate] dayOfWeek]);
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, v];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceMonthly)
|
||||
{
|
||||
@@ -132,9 +111,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if (firstOccurrence < 0)
|
||||
firstOccurrence = 5;
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, firstOccurrence];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
|
||||
}
|
||||
else if ([[self byMonthDay] count])
|
||||
{
|
||||
@@ -148,9 +126,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
iCalByDayMask *dm;
|
||||
|
||||
dm = [self byDayMask];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, 5];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", 5];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,7 +139,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// Simple reccurrence rule of type "Monthly"
|
||||
type = 2;
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%d</Recurrence_DayOfMonth>", t, [[self _adjustedStartDate] dayOfMonth]];
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
|
||||
[[[self parent] startDate] dayOfMonth]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
|
||||
@@ -181,39 +159,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if (firstOccurrence < 0)
|
||||
firstOccurrence = 5;
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, firstOccurrence];
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%@</Recurrence_MonthOfYear>", t,
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
|
||||
[self flattenedValuesForKey: @"bymonth"]];
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 5; // Yearly
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%@</Recurrence_DayOfMonth>", t,
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%@</Recurrence_DayOfMonth>",
|
||||
[self flattenedValuesForKey: @"bymonthday"]];
|
||||
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%@</Recurrence_MonthOfYear>", t,
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
|
||||
[self flattenedValuesForKey: @"bymonth"]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 5;
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%d</Recurrence_DayOfMonth>", t, [[self _adjustedStartDate] dayOfMonth]];
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%d</Recurrence_MonthOfYear>", t, [[self _adjustedStartDate] monthOfYear]];
|
||||
}
|
||||
type = 5;
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Recurrence_Type xmlns=\"%@:\">%d</Recurrence_Type>", t, type];
|
||||
|
||||
if ([[self parent] isKindOfClass: [iCalToDo class]])
|
||||
[s appendFormat: @"<Recurrence_Start xmlns=\"%@:\">%@</Recurrence_Start>", t, [[[self parent] startDate] activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Recurrence_Type xmlns=\"Calendar:\">%d</Recurrence_Type>", type];
|
||||
|
||||
// Occurrences / Until
|
||||
//[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%d</Recurrence_Occurrences>", 5];
|
||||
if ([self repeatCount])
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"%@:\">%@</Recurrence_Occurrences>", t,
|
||||
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%@</Recurrence_Occurrences>",
|
||||
[self flattenedValuesForKey: @"count"]];
|
||||
}
|
||||
else if ([self untilDate])
|
||||
@@ -224,10 +196,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//ud = [[context activeUser] userDefaults];
|
||||
//[date setTimeZone: [ud timeZone]];
|
||||
|
||||
[s appendFormat: @"<Recurrence_Until xmlns=\"%@:\">%@</Recurrence_Until>", t,
|
||||
[s appendFormat: @"<Recurrence_Until xmlns=\"Calendar:\">%@</Recurrence_Until>",
|
||||
[date activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
[s appendString: @"</Recurrence>"];
|
||||
|
||||
return s;
|
||||
|
||||
@@ -31,10 +31,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
|
||||
#include "NSData+ActiveSync.h"
|
||||
|
||||
@@ -78,28 +83,10 @@ struct SYSTEMTIME {
|
||||
tzData->wDay = ([mask firstOccurrence] == -1) ? 5 : [mask firstOccurrence];
|
||||
|
||||
dateValue = [self startDate];
|
||||
|
||||
if (![dateValue hourOfDay])
|
||||
{
|
||||
if ([mask firstDay]-1 < 0)
|
||||
tzData->wDayOfWeek = 6;
|
||||
else
|
||||
tzData->wDayOfWeek = [mask firstDay]-1;
|
||||
|
||||
tzData->wHour = 23;
|
||||
tzData->wMinute = 59;
|
||||
tzData->wSecond = 59;
|
||||
tzData->wMilliseconds = 999;
|
||||
}
|
||||
else
|
||||
{
|
||||
tzData->wDayOfWeek = [mask firstDay];
|
||||
|
||||
tzData->wHour = [dateValue hourOfDay];
|
||||
tzData->wMinute = [dateValue minuteOfHour];
|
||||
tzData->wSecond = [dateValue secondOfMinute];
|
||||
tzData->wMilliseconds = 0;
|
||||
}
|
||||
tzData->wHour = [dateValue hourOfDay];
|
||||
tzData->wMinute = [dateValue minuteOfHour];
|
||||
tzData->wSecond = [dateValue secondOfMinute];
|
||||
tzData->wMilliseconds = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +128,7 @@ struct SYSTEMTIME {
|
||||
//uint16_t wStandardYear;
|
||||
struct SYSTEMTIME stStandardDate;
|
||||
//uint16_t wDaylightYear;
|
||||
struct SYSTEMTIME stDaylightDate = {0,0,0,0,0,0,0,0};
|
||||
struct SYSTEMTIME stDaylightDate;
|
||||
|
||||
char standardName[64], daylightName[64];
|
||||
|
||||
@@ -157,17 +144,13 @@ struct SYSTEMTIME {
|
||||
|
||||
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
|
||||
if (!period)
|
||||
{
|
||||
stStandardDate.wMonth = 0;
|
||||
lDaylightBias = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
|
||||
[period _fillTZDate: &stDaylightDate];
|
||||
//wStandardYear = stStandardDate.wYear;
|
||||
//wDaylightYear = stDaylightDate.wYear;
|
||||
}
|
||||
stStandardDate.wMonth = 0;
|
||||
|
||||
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
|
||||
[period _fillTZDate: &stDaylightDate];
|
||||
//wStandardYear = stStandardDate.wYear;
|
||||
//wDaylightYear = stDaylightDate.wYear;
|
||||
|
||||
|
||||
// We build the timezone
|
||||
[bytes appendBytes: &lBias length: 4];
|
||||
|
||||
@@ -29,12 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#import "iCalToDo+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
@@ -42,32 +45,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
#include "iCalRecurrenceRule+ActiveSync.h"
|
||||
#include "iCalAlarm+ActiveSync.h"
|
||||
|
||||
@implementation iCalToDo (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSArray *categories;
|
||||
id o;
|
||||
|
||||
int v, i;
|
||||
int v;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
// Complete
|
||||
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
|
||||
o = [self completed];
|
||||
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
|
||||
|
||||
// DateCompleted
|
||||
if ((o = [self completed]))
|
||||
if (o)
|
||||
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Start date
|
||||
@@ -84,10 +82,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<DueDate xmlns=\"Tasks:\">%@</DueDate>", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<UTCDueDate xmlns=\"Tasks:\">%@</UTCDueDate>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Importance
|
||||
o = [self priority];
|
||||
@@ -99,54 +93,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
v = 1;
|
||||
[s appendFormat: @"<Importance xmlns=\"Tasks:\">%d</Importance>", v];
|
||||
|
||||
// Reminder
|
||||
if ([self hasAlarms])
|
||||
{
|
||||
iCalAlarm *alarm;
|
||||
NSString *webstatus;
|
||||
|
||||
if ((alarm = [self firstSupportedAlarm]))
|
||||
{
|
||||
webstatus = [[alarm trigger] value: 0 ofAttribute: @"x-webstatus"];
|
||||
if (!webstatus || ([webstatus caseInsensitiveCompare: @"TRIGGERED"] != NSOrderedSame))
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 1];
|
||||
else
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
|
||||
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
}
|
||||
// Reminder - FIXME
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
|
||||
// Sensitivity - FIXME
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", 0];
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
v = 3;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Tasks:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Tasks:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
// Subject
|
||||
o = [self summary];
|
||||
if ([o length])
|
||||
@@ -154,25 +106,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ((o = [self comment]))
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Tasks:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Tasks:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", (int)[o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -183,6 +125,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
NSInteger tzOffset;
|
||||
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
@@ -192,16 +136,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setSummary: o];
|
||||
|
||||
// FIXME: merge with iCalEvent
|
||||
if ([[context objectForKey: @"ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
|
||||
|
||||
if ([[theValues objectForKey: @"Complete"] intValue] &&
|
||||
((o = [theValues objectForKey: @"DateCompleted"])) )
|
||||
@@ -210,32 +147,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
o = [o calendarDate];
|
||||
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
|
||||
//tzOffset = [[o timeZone] secondsFromGMTForDate: o];
|
||||
//o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
// hours: 0 minutes: 0
|
||||
// seconds: -tzOffset];
|
||||
[completed setDate: o];
|
||||
[self setStatus: @"COMPLETED"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setStatus: @"IN-PROCESS"];
|
||||
[self setCompleted: nil];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"DueDate"]))
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
|
||||
[due setTimeZone: tz];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"StartDate"]))
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
[due setTimeZone: tz];
|
||||
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
@@ -250,65 +182,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self setPriority: @"9"];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- normal, 1- personal, 2- private and 3-confidential
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"Sensitivity"]))
|
||||
{
|
||||
switch ([o intValue])
|
||||
{
|
||||
case 2:
|
||||
[self setAccessClass: @"PRIVATE"];
|
||||
break;
|
||||
case 3:
|
||||
[self setAccessClass: @"CONFIDENTIAL"];
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
default:
|
||||
[self setAccessClass: @"PUBLIC"];
|
||||
}
|
||||
}
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"ReminderTime"]))
|
||||
{
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [[iCalAlarm alloc] init];
|
||||
[alarm takeActiveSyncValues: theValues inContext: context];
|
||||
|
||||
[self removeAllAlarms];
|
||||
[self addToAlarms: alarm];
|
||||
RELEASE(alarm);
|
||||
|
||||
}
|
||||
|
||||
// Recurrence
|
||||
if ((o = [theValues objectForKey: @"Recurrence"]) && !([[o objectForKey: @"Recurrence_DeadOccur"] intValue]))
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
rule = [[iCalRecurrenceRule alloc] init];
|
||||
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
|
||||
RELEASE(rule);
|
||||
|
||||
[rule takeActiveSyncValues: o inContext: context];
|
||||
|
||||
if (!([theValues objectForKey: @"StartDate"]))
|
||||
{
|
||||
iCalDateTime *start;
|
||||
|
||||
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
|
||||
[start setTimeZone: tz];
|
||||
[start setDate: [[o objectForKey: @"Recurrence_Start"] calendarDate]];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -28,7 +28,7 @@
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
|
||||
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
|
||||
<Location />
|
||||
<IfVersion < 2.4>
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
@@ -40,7 +40,7 @@
|
||||
<Proxy http://127.0.0.1:20000>
|
||||
RequestHeader set "x-webobjects-server-port" "8843"
|
||||
RequestHeader set "x-webobjects-server-name" "CHANGETHIS:8843"
|
||||
RequestHeader set "x-webobjects-server-url" "https://CHANGETHIS:8843"
|
||||
RequestHeader set "x-webobjects-server-url" "http://CHANGETHIS:8843"
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
AddDefaultCharset UTF-8
|
||||
</Proxy>
|
||||
|
||||
+11
-30
@@ -6,7 +6,7 @@ Alias /SOGo/WebServerResources/ \
|
||||
<Directory /usr/lib/GNUstep/SOGo/>
|
||||
AllowOverride None
|
||||
|
||||
<IfVersion < 2.4>
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
@@ -22,14 +22,6 @@ Alias /SOGo/WebServerResources/ \
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
# Don't send the Referer header for cross-origin requests
|
||||
Header always set Referrer-Policy "same-origin"
|
||||
|
||||
<Location /SOGo>
|
||||
# Don't cache dynamic content
|
||||
Header set Cache-Control "max-age=0, no-cache, no-store"
|
||||
</Location>
|
||||
|
||||
## Uncomment the following to enable proxy-side authentication, you will then
|
||||
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
|
||||
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
|
||||
@@ -53,12 +45,8 @@ Header always set Referrer-Policy "same-origin"
|
||||
#</Location>
|
||||
|
||||
ProxyRequests Off
|
||||
ProxyPreserveHost On
|
||||
SetEnv proxy-nokeepalive 1
|
||||
|
||||
# Uncomment the following lines if you experience "Bad gateway" errors with mod_proxy
|
||||
#SetEnv proxy-initial-not-pooled 1
|
||||
#SetEnv force-proxy-request-1.0 1
|
||||
ProxyPreserveHost On
|
||||
|
||||
# When using CAS, you should uncomment this and install cas-proxy-validate.py
|
||||
# in /usr/lib/cgi-bin to reduce server overloading
|
||||
@@ -69,8 +57,7 @@ SetEnv proxy-nokeepalive 1
|
||||
# Allow from your-cas-host-addr
|
||||
# </Proxy>
|
||||
|
||||
# Redirect / to /SOGo
|
||||
#RedirectMatch ^/$ https://mail.yourdomain.com/SOGo
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
# Enable to use Microsoft ActiveSync support
|
||||
# Note that you MUST have many sogod workers to use ActiveSync.
|
||||
@@ -80,24 +67,18 @@ SetEnv proxy-nokeepalive 1
|
||||
# http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
|
||||
# retry=60 connectiontimeout=5 timeout=360
|
||||
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
|
||||
|
||||
<Proxy http://127.0.0.1:20000/SOGo>
|
||||
## Adjust the following to your configuration
|
||||
## and make sure to enable the headers module
|
||||
<IfModule headers_module>
|
||||
RequestHeader set "x-webobjects-server-port" "443"
|
||||
SetEnvIf Host (.*) HTTP_HOST=$1
|
||||
RequestHeader set "x-webobjects-server-name" "%{HTTP_HOST}e" env=HTTP_HOST
|
||||
RequestHeader set "x-webobjects-server-url" "https://%{HTTP_HOST}e" env=HTTP_HOST
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "443"
|
||||
RequestHeader set "x-webobjects-server-name" "yourhostname"
|
||||
RequestHeader set "x-webobjects-server-url" "https://yourhostname"
|
||||
|
||||
## When using proxy-side autentication, you need to uncomment and
|
||||
## adjust the following line:
|
||||
RequestHeader unset "x-webobjects-remote-user"
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
|
||||
RequestHeader unset "x-webobjects-remote-user"
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
|
||||
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
</IfModule>
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
@@ -109,5 +90,5 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
|
||||
</IfModule>
|
||||
|
||||
-4697
File diff suppressed because it is too large.
Load diff
+5655
File diff suppressed because it is too large.
Load diff
+5
-26
@@ -1,29 +1,8 @@
|
||||
all: pdf html
|
||||
all: $(patsubst %.asciidoc,%.pdf,$(wildcard *.asciidoc))
|
||||
|
||||
ASCIIDOCS = $(wildcard SOGo*.asciidoc)
|
||||
PDFS = $(patsubst %.asciidoc,%.pdf, $(ASCIIDOCS))
|
||||
HTML = $(patsubst %.asciidoc,%.html, $(ASCIIDOCS))
|
||||
|
||||
%.pdf: %.asciidoc asciidoctor-pdf-theme.yml $(wildcard includes/*.asciidoc)
|
||||
asciidoctor-pdf \
|
||||
-a pdf-fontsdir=fonts \
|
||||
-a release_version=`git describe --abbrev=0 --tags | cut -d'-' -f 2` \
|
||||
-a release_month=`LANG=en_US.UTF-8 date +%B` \
|
||||
-a pdf-theme=asciidoctor-pdf-theme.yml \
|
||||
--trace \
|
||||
$<
|
||||
|
||||
%.html: %.asciidoc $(wildcard includes/*.asciidoc)
|
||||
asciidoctor \
|
||||
-D . \
|
||||
-a release_version=`git describe --abbrev=0 --tags | cut -d'-' -f 2` \
|
||||
-a release_month=`LANG=en_US.UTF-8 date +%B` \
|
||||
-n \
|
||||
$<
|
||||
|
||||
pdf: $(PDFS)
|
||||
|
||||
html: $(HTML)
|
||||
%.pdf : %.asciidoc
|
||||
asciidoc -a docinfo1 -b docbook -d book -o $<.docbook $<
|
||||
fop -c fonts/fop-config.xml -xsl docbook/xsl/sogo-fo.xsl -xml $<.docbook -pdf $@
|
||||
|
||||
clean:
|
||||
rm -f *.pdf *.html
|
||||
rm *.asciidoc.docbook *.pdf
|
||||
@@ -1,194 +0,0 @@
|
||||
Developer's Guide
|
||||
=================
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See includes/global-attributes.asciidoc
|
||||
for authors, copyright and license information.
|
||||
|
||||
////
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
UI and UX
|
||||
---------
|
||||
|
||||
* https://material.io/design/
|
||||
|
||||
Frameworks & Tools
|
||||
------------------
|
||||
|
||||
GNUstep
|
||||
~~~~~~~
|
||||
|
||||
SOPE
|
||||
~~~~
|
||||
|
||||
JavaScript libraries
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* https://angularjs.org/
|
||||
* https://material.angularjs.org/
|
||||
* http://angular-ui.github.io/ui-router/
|
||||
* http://lodash.com/
|
||||
* https://github.com/nervgh/angular-file-upload
|
||||
* https://github.com/a5hik/ng-sortable
|
||||
|
||||
Code Style
|
||||
----------
|
||||
|
||||
Objective-C
|
||||
~~~~~~~~~~~
|
||||
|
||||
* To document the Web APIs, we follow the http://apidocjs.com/[APIDOC] standards.
|
||||
|
||||
apidoc -f ".*\\.m" -i UI -o Documentation/JSON-API
|
||||
|
||||
* When returning JSON from an object extending UIxComponent, use the following method:
|
||||
|
||||
- (WOResponse *) responseWithStatus: (unsigned int) status
|
||||
andJSONRepresentation: (NSObject *) contentObject;
|
||||
|
||||
HTML
|
||||
~~~~
|
||||
|
||||
* Localize your strings:
|
||||
|
||||
<var:string label:value="I'm localized!"/>
|
||||
|
||||
* Localize your attributes:
|
||||
|
||||
<input type="text" label:placeholder="I'm localized!"/>
|
||||
|
||||
* Reuse existing localized strings as much as possible. Otherwise don't forget to update the English Localizable.strings file of the appropriate module.
|
||||
|
||||
JavaScript
|
||||
~~~~~~~~~~
|
||||
|
||||
* http://eslint.org/
|
||||
* http://standardjs.com
|
||||
* https://github.com/toddmotto/angularjs-styleguide
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CODING.md
|
||||
* http://jshint.com/
|
||||
* https://github.com/angular/material/tree/master/docs/guides
|
||||
|
||||
* We conform to https://github.com/airbnb/javascript[Airbnb coding standards]. Use https://github.com/jscs-dev/node-jscs[jscs] with the 'airbnb' preset to validate your code style:
|
||||
|
||||
jscs -p airbnb *.js
|
||||
|
||||
* For documentation, we follow the http://usejsdoc.org/[JSDoc3] standards:
|
||||
|
||||
jsdoc UI/WebServerResources/js/{Common,Contacts,Mailer,Preferences,Scheduler}/*.js -d Documentation/JavaScript-API
|
||||
|
||||
Models (facades)
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
////
|
||||
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/
|
||||
////
|
||||
* Move business logic into models and share them.
|
||||
* Keep it simple, separate server interaction and error handling from the model. That way model only handle data processing and code is easier to maintain.
|
||||
|
||||
Controllers
|
||||
^^^^^^^^^^^
|
||||
|
||||
* Functions not exposed in the controller must be prefixed with an underscore.
|
||||
|
||||
SASS/CSS
|
||||
~~~~~~~~
|
||||
|
||||
* http://componentcss.com/
|
||||
* https://github.com/styleguide/css
|
||||
* https://smacss.com/
|
||||
* http://cssguidelin.es/
|
||||
* http://sixrevisions.com/css/css-methodologies/
|
||||
* https://css-tricks.com/what-a-css-code-review-might-look-like/
|
||||
* http://una.im/classy-css/
|
||||
* http://stylelint.io/
|
||||
|
||||
A `@mixin` is like a stamp: it creates a duplicated version of the property block (optionally) with arguments provided. An `@extend` appends the element you are extending to the property block. It is your "yes, and ___" statement.
|
||||
|
||||
* For documentation, we follow http://sassdoc.com/[SassDoc] annotations.
|
||||
* FlexBox compatibility http://caniuse.com/#feat=flexbox
|
||||
|
||||
Fonts
|
||||
^^^^^
|
||||
|
||||
* http://mozilla.github.io/Fira/[Mozilla Fira]
|
||||
* https://material.io/tools/icons/[Material icons]
|
||||
|
||||
Building frontend
|
||||
-----------------
|
||||
|
||||
* Install the latest stable release of https://nodejs.org[Node.js]
|
||||
* Install grunt
|
||||
|
||||
npm install -g grunt-cli
|
||||
npm install -g bower
|
||||
|
||||
* We need the SASS files of Angular Material to build our CSS. The git repository of Angular Material is included as a submodule of SOGo:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
* Generate the JavaScript and CSS files
|
||||
|
||||
cd UI/WebServerResources
|
||||
npm install
|
||||
bower install
|
||||
grunt build
|
||||
|
||||
Defining an alternate color theme
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
SOGo relies on the https://material.angularjs.org/latest/Theming/01_introduction[theming system of Angular Material] to define the colors of the Web interface.
|
||||
|
||||
To overwrite the default theme in SOGo, set the following parameter in `/etc/sogo/sogo.conf`:
|
||||
|
||||
SOGoUIAdditionalJSFiles = (js/theme.js);
|
||||
|
||||
Edit `theme.js` under `/usr/lib64/GNUstep/SOGo/WebServerResources/js` or `/usr/lib/GNUstep/SOGo/WebServerResources/js` depending on your platform and restart sogod.
|
||||
|
||||
If the configuration parameter `SOGoUIxDebugEnabled` is unset or set to `NO` in `/etc/sogo/sogo.conf`, you'll need to generate a new `theme-default.css` stylesheet for the new theme.
|
||||
|
||||
. Temporarily set `SOGoUIxDebugEnabled` to `YES`;
|
||||
. Restart sogod;
|
||||
. From your favorite browser, open the JavaScript console and type the following:
|
||||
|
||||
copy([].slice.call(document.styleSheets)
|
||||
.map(e => e.ownerNode)
|
||||
.filter(e => e.hasAttribute('md-theme-style'))
|
||||
.map(e => e.textContent)
|
||||
.join('\n')
|
||||
)
|
||||
|
||||
. Overwrite the content of `WebServerResources/css/theme-default.css` with the content of the clipboard;
|
||||
. Restore the value of `SOGoUIxDebugEnabled` (`NO` or unset);
|
||||
. Restart sogod.
|
||||
|
||||
Version Control
|
||||
---------------
|
||||
|
||||
* https://devcharm.com/articles/46/improve-your-git-workflow/
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CONTRIBUTING.md#-commit-message-format
|
||||
* Each commit should cover only one thing;
|
||||
* Begin the commit message with a single short (less than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description;
|
||||
* When fixing a bug, commit to the devel branch as well as the maintenance branch of the latest release version (named maintenance/x.y). When a ticket is associated to the bug, add to the description a line saying *Fixes #1234*.
|
||||
* `git pull` may introduce http://stackoverflow.com/questions/15316601/in-what-cases-could-git-pull-be-harmful[inconsistencies and problems]. Replace it with the following alias:
|
||||
|
||||
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
* https://github.com/angular/protractor
|
||||
* http://karma-runner.github.io/
|
||||
|
||||
JSON API
|
||||
~~~~~~~~
|
||||
|
||||
One practical way to test the JSON API is to use `curl`. To do so, you need to enable `SOGoTrustProxyAuthentication` and configure HTTP authentifcation in Apache. You can pipe the result to http://stedolan.github.io/jq/[jq] to nicely format and filter the output:
|
||||
|
||||
curl -u username:password http://localhost/SOGo/so/username/Calendar/calendarslist | jq '.'
|
||||
|
||||
curl -u username:password -H 'Content-Type: application/json' -d '{}' http://localhost/SOGo/so/francis/Calendar/personal/71B6-54904400-1-7C308500.ics/save
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,13 +1,15 @@
|
||||
Mobile Devices Configuration Guide
|
||||
==================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See includes/global-attributes.asciidoc
|
||||
for authors, copyright and license information.
|
||||
See SOGo Mobile Devices Configuration-docinfo.xml for authors,
|
||||
copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
@@ -22,7 +24,7 @@ devices (iPhone, iPod touch, and iPad).
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available at
|
||||
https://www.sogo.nu/support.html#/documentation.
|
||||
http://www.sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
Mozilla Thunderbird Configuration Guide
|
||||
=======================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See includes/global-attributes.asciidoc
|
||||
for authors, copyright and license information.
|
||||
See SOGo Mozilla Thunderbird Configuration Guide-docinfo.xml for
|
||||
authors, copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
@@ -46,7 +48,7 @@ device, or Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found on
|
||||
https://www.sogo.nu/.
|
||||
http://www.sogo.nu/.
|
||||
|
||||
Installation
|
||||
------------
|
||||
@@ -59,8 +61,9 @@ Mozilla Thunderbird
|
||||
|
||||
Mozilla Thunderbird is the official front end client of SOGo.
|
||||
|
||||
Mozilla Thunderbird versions 31, 38, 45 and above are supported
|
||||
and it is recommended to use the latest version of Thunderbird.
|
||||
Mozilla Thunderbird version 2, 3.1, 10 ESR (Extended Support Release),
|
||||
17 ESR, 24 and 31 are supported and it is recommended to use version 31 of
|
||||
Thunderbird.
|
||||
|
||||
In order to download and install Mozilla Thunderbird, please visit:
|
||||
|
||||
@@ -69,16 +72,33 @@ https://www.mozilla.org/en-US/thunderbird/organizations/all-esr.html
|
||||
Mozilla Lightning
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When using Thunderbird, you can use the latest version of Mozilla
|
||||
Lightning. Use the Add-ons manager of Thunderbird or visit:
|
||||
When using version 24 or 31 of Thunderbird, you can use the latest version of
|
||||
Mozilla Lightning. Use the Add-ons manager of Thunderbird or visit:
|
||||
|
||||
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/
|
||||
|
||||
When using version 17 ESR of Thunderbird, you can use Mozilla Lightning
|
||||
version 1.9.1. In order to download the extension, please visit:
|
||||
|
||||
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/versions/1.9.1
|
||||
|
||||
For Thunderbird 2 and 3.1, you need the _Inverse Edition_of Mozilla
|
||||
Lightning. It provides back ported features, bug fixes and security
|
||||
fixes from the current development version of Mozilla Lightning. For
|
||||
Thunderbird 2, it is based on release version 0.9 of Lightning. For
|
||||
Thunderbird 3.1, it is based on 1.0b2.
|
||||
|
||||
In order to download and install Mozilla Lightning – Inverse Edition for
|
||||
Thunderbird 2 or 3.1, please visit:
|
||||
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
|
||||
SOGo Connector and SOGo Integrator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The SOGo Connector and Integrator extensions are provided to perfect the
|
||||
integration of Mozilla Thunderbird with the SOGo groupware solution.
|
||||
integration of Mozilla Thunderbird 2, 3.1, 10 ESR, 17 ESR, 24 and 31 with
|
||||
the SOGo groupware solution.
|
||||
|
||||
First of all, the SOGo Connector extension transforms Thunderbird into a
|
||||
full DAV client for groupware servers such as SOGo, eGroupware or
|
||||
@@ -116,7 +136,7 @@ extensions, please visit:
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
|
||||
Prior to installing the SOGo Integrator extension, you should read the
|
||||
following chapter - _SOGo Integrator Customization_.
|
||||
following chapter – _SOGo Integrator Customization_.
|
||||
|
||||
SOGo Integrator Customization
|
||||
-----------------------------
|
||||
@@ -137,7 +157,7 @@ the same user name used to connect to the first email server configured
|
||||
in Thunderbird. It is a current limitation but it will fit nearly all
|
||||
configurations out there.
|
||||
|
||||
For testing purpose, it is strongly recommended to create and
|
||||
For testing purpose, you are strongly recommended to create and
|
||||
configure an additional user profile for Thunderbird. This is for two
|
||||
reasons. The first is because of the limitation mentioned above. The
|
||||
second is because the Integrator will synchronize your personal address
|
||||
@@ -148,7 +168,7 @@ you may want to make a copy of that address book beforehand.
|
||||
The second part requires editing one file in the extension file sub tree
|
||||
to specify where the SOGo server is located. This is done by hand. In an
|
||||
enterprise environment, this step is only required once per release
|
||||
since the updates are expected to propagate automatically.
|
||||
since the updates are expected to propagate automatically.
|
||||
|
||||
Uncompress (using a ZIP or jar tool) the SOGo Integrator XPI and locate
|
||||
the following file:
|
||||
@@ -167,7 +187,7 @@ For example, one would replace:
|
||||
|
||||
by:
|
||||
|
||||
<Seq about="https://sogo.nu" isi:updateURL="https://sogo.acme.com/plugins/updates.php?plugin=%ITEM_ID%&version=%ITEM_VERSION%&platform=%PLATFORM%">
|
||||
<Seq about="http://inverse.ca/sogo-integrator/extensions" isi:updateURL="https://sogo.acme.com/plugins/updates.php?plugin=%ITEM_ID%&version=%ITEM_VERSION%&platform=%PLATFORM%">
|
||||
|
||||
if the SOGo server is accessible from the following URL:
|
||||
|
||||
@@ -175,7 +195,7 @@ if the SOGo server is accessible from the following URL:
|
||||
|
||||
Note that if you changed the `x-webobjects-server-url` configuration
|
||||
setting from your HTTP server configuration file for SOGo, the
|
||||
value *must* match the one you specify in `isi:updateURL` - even the
|
||||
value *must* match the one you specify in `isi:updateURL` – even the
|
||||
port number.
|
||||
|
||||
Moreover, you *must* change the value of the
|
||||
@@ -196,7 +216,7 @@ In this section, you will learn how to install and configure the SOGo
|
||||
Update Server.
|
||||
|
||||
The SOGo Update Server can be used to automatically install or uninstall
|
||||
Mozilla Thunderbird extensions, push user settings and more - all from a
|
||||
Mozilla Thunderbird extensions, push user settings and more – all from a
|
||||
central place managed by system administrators.
|
||||
|
||||
Installation
|
||||
@@ -259,7 +279,7 @@ The syntax is:
|
||||
----
|
||||
"<extension ID>"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "<exact version found in the extension's manifest.json file>",
|
||||
"version" => "<exact version found in the extension's install.rdf file>",
|
||||
"filename" => "<exact filename on the filesystem>" )
|
||||
----
|
||||
|
||||
|
||||
@@ -0,0 +1,758 @@
|
||||
Native Microsoft Outlook Configuration Guide
|
||||
============================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See SOGo Native Microsoft Outlook Configuration-docinfo.xml for
|
||||
authors, copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
the native Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
Prior going over this guide, you should have a working SOGo
|
||||
installation. Please refer to the _SOGo Installation and Configuration
|
||||
Guide_ for more information on installing and configuring SOGo.
|
||||
|
||||
This guide also includes instructions for configuring Microsoft Outlook
|
||||
with SOGo.
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available
|
||||
at http://www.sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
and by using a native client such as Mozilla Thunderbird and Lightning.
|
||||
|
||||
SOGo is standard-compliant. It supports CalDAV, CardDAV, GroupDAV, iMIP
|
||||
and iTIP and reuses existing IMAP, SMTP and database servers — making
|
||||
the solution easy to deploy and interoperable with many applications.
|
||||
|
||||
SOGo features:
|
||||
|
||||
* Scalable architecture suitable for deployments from dozen to many
|
||||
thousand users
|
||||
* Rich Web-based interface that shares the look and feel, the features
|
||||
and the data of Mozilla Thunderbird and Lightning
|
||||
* Improved integration with Mozilla Thunderbird and Lightning by using
|
||||
the SOGo Connector and the SOGo Integrator
|
||||
* Native compatibility for Microsoft Outlook 2003, 2007, 2010, and 2013
|
||||
* Two-way synchronization support with any Microsoft ActiveSync-capable
|
||||
device, and Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found
|
||||
on http://www.sogo.nu/.
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
The following diagram demonstrates the architecture of the native
|
||||
Outlook compatibility layer of SOGo.
|
||||
|
||||
image::images/openchange.png[]
|
||||
|
||||
With Samba 4 and OpenChange, Microsoft Outlook clients can communicate
|
||||
natively with SOGo using the Microsoft Exchange protocol, without
|
||||
requiring costly and hard-to-maintain third-party MAPI connectors for
|
||||
Microsoft Outlook.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Organizations generally have solutions to authenticate users such as
|
||||
LDAP servers or Microsoft Active Directory servers.
|
||||
|
||||
The solution being used will influence how users are provisioned in
|
||||
Samba 4, a key component for native Outlook compatibility in SOGo.
|
||||
|
||||
LDAP Server
|
||||
~~~~~~~~~~~
|
||||
|
||||
If your organization uses a LDAP server such OpenLDAP, Novell
|
||||
eDirectory, Apache Directory or any other solution, you must use
|
||||
Samba 4's internal directory server and synchronize the data between
|
||||
both.
|
||||
|
||||
Synchronization scripts are not provided and unless you have clear-text
|
||||
passwords of your existing users, they will have to be changed during
|
||||
your initial synchronization so that your LDAP's server passwords are
|
||||
identical to the ones from Samba 4.
|
||||
|
||||
Any modifications to your existing LDAP server (password change, user
|
||||
addition or deletion, etc.) will have to be replicated to Samba 4's
|
||||
internal directory server.
|
||||
|
||||
Note that if you install Samba 4 on a server that is already running a
|
||||
LDAP service, you will have to change to TCP port on which your LDAP
|
||||
server listens to. Samba 4 will use the TCP port 389 and it can't be
|
||||
changed.
|
||||
|
||||
For example, with OpenLDAP, you can use the `-h` parameter for `slapd`
|
||||
to make it listen on an other TCP port.
|
||||
|
||||
Microsoft Active Directory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If your organization uses Microsoft Active Directory, Samba 4 will need
|
||||
to be joined to your Active Directory domain, as a DC.
|
||||
|
||||
Samba 4 will be able to reuse all the information contained in Microsoft
|
||||
Active Directory and no synchronization process needs to be put in place
|
||||
as information will get replicated to Samba 4 automatically.
|
||||
|
||||
For more information on joining Samba 4 to an existing Microsoft Active
|
||||
Directory domain, please refer to the Samba 4 documentation available at
|
||||
the following URL:
|
||||
|
||||
http://wiki.samba.org/index.php/Samba4
|
||||
|
||||
More specifically, have a look at the `samba-tool domain join` command.
|
||||
Note that joining Samba 4 to your Active Directory domain as a member
|
||||
will currently not work. An authentication bug is present in Samba 4
|
||||
which then prevents all Outlook users to successfully authenticate
|
||||
through Samba 4. This issue has been reported to the Samba team and is
|
||||
being worked on.
|
||||
|
||||
Other or No Solution
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If your organization neither uses a LDAP server or Microsoft Active
|
||||
Directory, you can start using Samba 4 as your directory server.
|
||||
|
||||
Samba 4's directory can be queried over LDAP just like Microsoft Active
|
||||
Directory and can also serve as a domain controller for Windows-based
|
||||
environments.
|
||||
|
||||
For example, SOGo can very well use Samba 4's built-in directory server
|
||||
to authenticate users. A SOGoUserSources entry to achieve this wold look
|
||||
like this:
|
||||
|
||||
----
|
||||
su – sogo
|
||||
defaults write sogod SOGoUserSources '(
|
||||
{
|
||||
CNFieldName = displayName;
|
||||
IDFieldName = cn;
|
||||
UIDFieldName = sAMAccountName;
|
||||
baseDN = "cn=Users,dc=example,dc=com";
|
||||
bindDN = "cn=Administrator,cn=Users,dc=example,dc=com";
|
||||
bindFields = (
|
||||
sAMAccountName
|
||||
);
|
||||
bindPassword = "%1OpenChange";
|
||||
canAuthenticate = YES;
|
||||
displayName = "Shared Addresses";
|
||||
hostname = "127.0.0.1";
|
||||
id = samba;
|
||||
isAddressBook = YES;
|
||||
port = 389;
|
||||
}
|
||||
)'
|
||||
----
|
||||
|
||||
Please refer to the _SOGo Installation and Configuration Guide_ for more
|
||||
information regarding `SOGoUserSources`.
|
||||
|
||||
IMAP Server and Trust
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An IMAP server supporting the ACL, UIDPLUS and QRESYNC IMAP extensions
|
||||
is required, such as Cyrus IMAP version 2.4 or later, or Dovecot version
|
||||
2.1 or later. If your current IMAP server does not support these
|
||||
extensions, you can use Dovecot's proxying capabilities. The follow
|
||||
configuration example makes Dovecot proxy all IMAP request to an
|
||||
existing server:
|
||||
|
||||
----
|
||||
auth_mechanisms = plain login
|
||||
imapc_host = inverse.ca
|
||||
imapc_port = 993
|
||||
imapc_ssl = imaps
|
||||
imapc_ssl_verify = no
|
||||
mail_gid = imapproxy
|
||||
mail_home = /home/imapproxy/%u
|
||||
mail_location = imapc:~/imapc
|
||||
mail_uid = imapproxy
|
||||
passdb {
|
||||
args = host=inverse.ca ssl=imaps port=993 ssl_ca_dir=/etc/pki/tls/certs
|
||||
default_fields = userdb_imapc_user=%u userdb_imapc_password=%w
|
||||
driver = imap
|
||||
}
|
||||
protocols = imap
|
||||
ssl = no
|
||||
userdb {
|
||||
driver = prefetch
|
||||
}
|
||||
----
|
||||
|
||||
SOGo would then be configured to use Dovecot's proxy as the IMAP server.
|
||||
|
||||
Moreover, the authentication mode in use by Windows with Samba and
|
||||
Exchange servers prevent the backend from knowing the real password
|
||||
being used by the user. This implies that the IMAP server must accept
|
||||
any passwords from the host on which Samba is running.
|
||||
|
||||
To accomplish this with Cyrus IMAP Server, set `sasl_pwcheck_method`
|
||||
to `alwaystrue` in `/etc/imapd.conf`. You should restrain this to
|
||||
an `imapd` instance dedicated to SOGo.
|
||||
|
||||
For Dovecot, use an authentication source similar to:
|
||||
|
||||
----
|
||||
passdb {
|
||||
driver = static
|
||||
args = nopassword=y allow_nets=127.0.0.1/32
|
||||
}
|
||||
----
|
||||
|
||||
You should also make sure that you restrain this only to the SOGo
|
||||
processes.
|
||||
|
||||
For any other IMAP server, refer to the product's documentation. If such
|
||||
capability is not offered, you can alternatively define the cleartext
|
||||
password for each user. Please refer to the _Adding Users_ section from
|
||||
this document.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This section will guide you through the installation of the native
|
||||
Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
Red Hat Enterprise Linux v6 x86_64
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
|
||||
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
|
||||
available from SOGo's web site. Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend_nightly.html.
|
||||
|
||||
In order to satisfy certain dependencies, you should also add the EPEL
|
||||
source corresponding to your distribution and architecture. More
|
||||
information on this is available here:
|
||||
http://fedoraproject.org/wiki/EPEL – or more specifically,
|
||||
http://fedoraproject.org/wiki/EPEL/FAQ#How_can_I_install_the_packages_from_the_EPEL_software_repository.3F.
|
||||
|
||||
Once ready, install the OpenChange packages on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
yum clean all && yum makecache
|
||||
yum install samba \
|
||||
openchange \
|
||||
sogo-openchange-backend \
|
||||
openchange-ocsmanager \
|
||||
openchange-rpcproxy \
|
||||
mysql-server \
|
||||
MySQL-python
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
[NOTE]
|
||||
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
|
||||
CentOS 6 i386 and CentOS 7.
|
||||
|
||||
Debian 7.0 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
SOGo, OpenChange and the SOGo OpenChange backend are now
|
||||
available from SOGo's web site. Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend.html to setup your
|
||||
apt sources.
|
||||
|
||||
For Samba 4, you need to use the _wheezy-backports_ repository. To do so, create
|
||||
`/etc/apt/sources.list.d/backports.list`:
|
||||
|
||||
deb http://http.debian.net/debian wheezy-backports main
|
||||
|
||||
On Ubuntu 12.04, you will also have to add the Wheezy sources:
|
||||
|
||||
deb http://ftp.us.debian.org/debian wheezy main
|
||||
deb http://security.debian.org/ wheezy/updates main
|
||||
|
||||
Then install Samba 4 on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
apt-get update
|
||||
apt-get -t wheezy-backports install samba samba-dev
|
||||
----
|
||||
|
||||
Once completed, install the packages related to OpenChange and the SOGo
|
||||
provider:
|
||||
|
||||
----
|
||||
apt-get install openchangeserver \
|
||||
sogo-openchange \
|
||||
openchangeproxy \
|
||||
python-ocsmanager \
|
||||
mysql-server \
|
||||
python-mysqldb
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
[NOTE]
|
||||
On Ubuntu 12.04, the Samba init scripts need to be modified to
|
||||
disable the upstart check. For more details, refer to:
|
||||
https://wiki.samba.org/index.php/Samba4/InitScript
|
||||
|
||||
|
||||
Ubuntu 14.04 (Trusty Tahr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For Ubuntu 14.04, you must not use the Debian Wheezy backports.
|
||||
|
||||
Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend.html to setup your
|
||||
apt sources.
|
||||
|
||||
Then install Samba 4 on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
apt-get update
|
||||
apt-get install samba samba-dev
|
||||
----
|
||||
|
||||
Once completed, install the packages related to OpenChange and the SOGo
|
||||
provider:
|
||||
|
||||
----
|
||||
apt-get install openchangeserver \
|
||||
sogo-openchange \
|
||||
openchangeproxy \
|
||||
python-ocsmanager \
|
||||
mysql-server \
|
||||
python-mysqldb
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
In this section, you'll learn how to configure the native Microsoft
|
||||
Outlook compatibility layer that SOGo offers.
|
||||
|
||||
SOGo Configuration
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
First thing to do is to configure SOGo to use your current services,
|
||||
which are your IMAP, SMTP and SQL database servers. The configuration
|
||||
instructions for this are available in the SOGo Installation and
|
||||
Configuration Guide available from http://www.sogo.nu/.
|
||||
|
||||
Please refer to that documentation before continuing with the
|
||||
instructions included in this guide.
|
||||
|
||||
Samba 4 Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Run the following commands as root:
|
||||
|
||||
----
|
||||
samba-tool domain provision --realm=example.com \
|
||||
--domain=OPENCHANGE \
|
||||
--adminpass='%1OpenChange' \
|
||||
--server-role='domain controller'
|
||||
|
||||
samba-tool user setexpiry administrator --noexpiry
|
||||
----
|
||||
|
||||
You might consider changing the realm and domain used, to suit your
|
||||
enviroment.
|
||||
|
||||
You might also have to
|
||||
remove `/etc/samba/smb.conf` prior running this command.
|
||||
|
||||
Add the following parameters to the `[global]` section of the
|
||||
`/etc/samba/smb.conf` configuration file:
|
||||
|
||||
----
|
||||
### Configuration required by OpenChange server ###
|
||||
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
|
||||
dcerpc_mapiproxy:server = true
|
||||
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
|
||||
### Configuration required by OpenChange server ###
|
||||
----
|
||||
|
||||
Your Samba 4 configuration file should look like this:
|
||||
|
||||
----
|
||||
# Global parameters
|
||||
[global]
|
||||
server role = active directory domain controller
|
||||
workgroup = EXAMPLE
|
||||
realm = example.com
|
||||
netbios name = sogo
|
||||
passdb backend = samba4
|
||||
### Configuration required by OpenChange server ###
|
||||
dcerpc endpoint servers = +epmapper, +mapiproxy
|
||||
dcerpc_mapiproxy:server = true
|
||||
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
|
||||
### Configuration required by OpenChange server ###
|
||||
|
||||
[netlogon]
|
||||
path = /var/lib/samba/sysvol/example.com/scripts
|
||||
read only = No
|
||||
|
||||
[sysvol]
|
||||
path = /var/lib/samba/sysvol
|
||||
read only = No
|
||||
----
|
||||
|
||||
OpenChange Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
|
||||
|
||||
First, create the OpenChange MySQL user:
|
||||
|
||||
----
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE USER 'openchange-user'@'localhost' IDENTIFIED BY 'openchange$123';
|
||||
mysql> GRANT ALL PRIVILEGES ON `openchange`.* TO 'openchange-user'@'localhost' WITH GRANT OPTION;
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
----
|
||||
|
||||
The Samba AD schema needs to be filled with additional object
|
||||
definitions by running the following commands:
|
||||
|
||||
----
|
||||
openchange_provision --standalone
|
||||
|
||||
NOTE: This operation can take several minutes
|
||||
[+] Step 1: Register Exchange OIDs
|
||||
[+] Step 2: Add Exchange attributes to Samba schema
|
||||
[+] Step 3: Add Exchange auxiliary classes to Samba schema
|
||||
[+] Step 4: Add Exchange objectCategory to Samba schema
|
||||
[+] Step 5: Add Exchange containers to Samba schema
|
||||
[+] Step 6: Add Exchange *sub* containers to Samba schema
|
||||
[+] Step 7: Add Exchange CfgProtocol subcontainers to Samba schema
|
||||
[+] Step 8: Add Exchange mailGateway subcontainers to Samba schema
|
||||
[+] Step 9: Add Exchange classes to Samba schema
|
||||
[+] Step 10: Add possSuperior attributes to Exchange classes
|
||||
[+] Step 11: Extend existing Samba classes and attributes
|
||||
[+] Step 12: Generic Exchange configuration objects
|
||||
[+] Step 13: Finalize generic Exchange configuration objects
|
||||
[SUCCESS] Done!
|
||||
[+] Step 1: Exchange Samba registration
|
||||
[SUCCESS] Done!
|
||||
[+] Step 1: Register Exchange Samba as the main server
|
||||
[SUCCESS] Done!
|
||||
----
|
||||
|
||||
Create the OpenChange database:
|
||||
|
||||
----
|
||||
openchange_provision --openchangedb --openchangedb-uri 'mysql://openchange-user:openchange$123@localhost/openchange'
|
||||
|
||||
Setting up openchange db
|
||||
[+] Public Folders
|
||||
===================
|
||||
* Public Folder Root : 0x0100000000000001 (72057594037927937)
|
||||
* IPM_SUBTREE : 0x0200000000000001 (144115188075855873)
|
||||
* NON_IPM_SUBTREE : 0x0300000000000001 (216172782113783809)
|
||||
* EFORMS REGISTRY : 0x0400000000000001 (288230376151711745)
|
||||
* OFFLINE ADDRESS BOOK : 0x0500000000000001 (360287970189639681)
|
||||
* /o=First Organization/cn=addrlists/cn=oabs/cn=Default Offline Address Book: 0x0600000000000001 (432345564227567617)
|
||||
* SCHEDULE+ FREE BUSY : 0x0700000000000001 (504403158265495553)
|
||||
* EX:/o=first organization/ou=first administrative group: 0x0800000000000001 (576460752303423489)
|
||||
* Events Root : 0x0900000000000001 (648518346341351425)
|
||||
----
|
||||
|
||||
Finally, modify `/etc/samba/smb.conf` to specify OpenChange connection information
|
||||
for its indexing database. Add the following at the end of the `[global]` section:
|
||||
|
||||
----
|
||||
mapistore:namedproperties = mysql
|
||||
namedproperties:mysql_user = openchange-user
|
||||
namedproperties:mysql_pass = openchange$123
|
||||
namedproperties:mysql_host = localhost
|
||||
namedproperties:mysql_db = openchange
|
||||
|
||||
mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
----
|
||||
|
||||
On RHEL, make sure SELinux is disabled:
|
||||
|
||||
setenforce 0
|
||||
|
||||
Next, you can start Samba using the usual command:
|
||||
|
||||
/etc/init.d/samba start
|
||||
|
||||
On upstart-based distributions, use:
|
||||
|
||||
start samba-ad-dc
|
||||
|
||||
You can also launch the OpenChange web services:
|
||||
|
||||
/etc/init.d/openchange-ocsmanager start
|
||||
|
||||
Apache Configuration for Web Services
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The OpenChange web services consist of two components:
|
||||
|
||||
1. *OCS Manager* which is used for autodiscovery and freebusy lookups on
|
||||
Outlook 2007 and 2010. This service runs in its own application server
|
||||
which listens on `127.0.0.1:5000` by default. Apache needs to be
|
||||
configured to forward certain requests to it to make it accessible from
|
||||
the outside.
|
||||
Note that this service *MUST* be accessible over*HTTPS*, otherwise Outlook
|
||||
won't use it.
|
||||
2. *RPC Proxy* which is used for RPC over HTTP ("Outlook Anywhere").
|
||||
This service runs as a WSGI application under apache (mod_wsgi).
|
||||
While HTTPS is not required to access this service, it is strongly
|
||||
recommended.
|
||||
|
||||
On RHEL-based distributions, the apache configuration required by these
|
||||
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
|
||||
`/etc/httpd/conf.d/rpcproxy.conf`.
|
||||
|
||||
For Debian-based distributions, these files can be found
|
||||
in `/etc/apache2/conf.d/`.
|
||||
|
||||
The configuration requires three Apache modules: _mod_proxy_,
|
||||
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
|
||||
might need to be activated on Debian-based installations:
|
||||
|
||||
a2enmod proxy proxy_http wsgi
|
||||
|
||||
On RHEL-based distributions, make sure the `LoadModule` directive is
|
||||
uncommented in `/etc/httpd/conf.d/wsgi.conf` (or
|
||||
`python26-mod_wsgi.conf` on RHELv5).
|
||||
|
||||
The _reqtimeout_ apache module is known to cause problems when using the
|
||||
default configuration shipped with Debian-based systems. On such
|
||||
distributions, apache will close (HTTP/1.1 500) any HTTP request for
|
||||
which the HTTP body hasn't arrived in 10 seconds.
|
||||
|
||||
While this is arguably good practice with regular HTTP, it will disrupt
|
||||
the RPC over HTTP protocol implemented by RPC Proxy: Outlook will
|
||||
continuously disconnect and reconnect leading to suboptimal performance.
|
||||
|
||||
To avoid this problem, use a much higher timeout or disable the module:
|
||||
|
||||
a2dismod reqtimeout
|
||||
|
||||
You should now restart the Apache service and make sure it will start on
|
||||
boot. On RHEL-based distributions, do:
|
||||
|
||||
chkconfig httpd on && /etc/init.d/httpd restart
|
||||
|
||||
On Debian-based distributions, do:
|
||||
|
||||
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
|
||||
|
||||
[NOTE]
|
||||
Debian-based distributions are not supported anymore for
|
||||
OCSManager/rpcproxy. Support will soon resume.
|
||||
|
||||
Name Service Configuration for Web Services
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The autodiscovery service must be made accessible in order to advertise
|
||||
the web services provided by OpenChange. This can be done in two ways.
|
||||
|
||||
1. The first is to associate the FQDN `autodiscover.example.com.` with
|
||||
the machine that hosts Samba 4 / OpenChange, by adding a `CNAME` entry
|
||||
in your DNS configuration. Note that, instead or changing your DNS
|
||||
server configuration, you can simply add a similar entry to the _hosts_
|
||||
file of the Windows machine from where you'll run Outlook, which is
|
||||
handy for testing purposes.
|
||||
2. The second option is to add a `SRV` entry to your DNS configuration
|
||||
where the `_service` value would be `Autodiscover` and the `_protocol`
|
||||
would be `_tcp`.
|
||||
|
||||
For example:
|
||||
|
||||
_autodiscover._tcp.example.com. IN SRV 0 0 443 sogo.example.com.
|
||||
|
||||
Again, the autodiscovery service must be accessible over HTTPS.
|
||||
|
||||
Adding Users
|
||||
------------
|
||||
|
||||
Users that wish to connect natively to SOGo must be provisioned in
|
||||
Samba 4 and in OpenChange – even if they already exist in your current
|
||||
LDAP or Microsoft Active Directory server.
|
||||
|
||||
To add a user, execute the following commands:
|
||||
|
||||
----
|
||||
# add user to samba
|
||||
samba-tool domain passwordsettings set --complexity=off
|
||||
samba-tool domain passwordsettings set --min-pwd-length=1
|
||||
samba-tool user add <username>
|
||||
samba-tool user setexpiry <username> --noexpiry
|
||||
# create user in openchange
|
||||
openchange_newuser --create <username>
|
||||
----
|
||||
|
||||
If you don't have a trust between your IMAP server and SOGo, you must at
|
||||
this point set the cleartext password of the newly created user in
|
||||
`/var/lib/samba/private/mapistore/<username/password`.
|
||||
|
||||
This per-user file contains the cleartext password of the user as a
|
||||
UTF-8 string, on a single line. This password will be used to
|
||||
authenticate SOGo/OpenChange storage provider to your IMAP server.
|
||||
|
||||
Microsoft Outlook Configuration
|
||||
-------------------------------
|
||||
|
||||
To connect Microsoft Outlook, you can either use the IP address of the
|
||||
server or its DNS name. If you prefer using the DNS name, add an entry
|
||||
like the following to the `c:\windows\system32\drivers\etc\hosts` file
|
||||
in order to associate the IP address with the right DNS names:
|
||||
|
||||
192.168.1.1 sogo.example.com autodiscover.example.com
|
||||
|
||||
Next, you must configure Microsoft Outlook.
|
||||
|
||||
* Open the Control Panel => Mail => Email Accounts.
|
||||
* Select _Add a new e-mail account_
|
||||
* Choose _Microsoft Exchange Server_
|
||||
* Fill the required information. Enter the DNS name or the IP address of
|
||||
your SOGo server in the _Microsoft Exchange Server_ field
|
||||
* Leave the _Use Cached Exchange Mode_ checkbox enabled
|
||||
* Enter your username in the _User Name_ field
|
||||
* Click on _More Settings_ and ignore the warning, if any, about
|
||||
Exchange being offline by clicking on Cancel
|
||||
* From the Security tab, enable Always prompt for user name and password
|
||||
* From the _Connection_ tab, enable _"Outlook Anywhere"_ if you plan to
|
||||
use Outlook outside of your LAN. Moreover, click on the _Exchange Proxy
|
||||
Settings..._ button to enable it for slow and fast networks. Specify
|
||||
also the host, which should be the same value you specified in the
|
||||
Microsoft Exchange Server field.
|
||||
* Finally, click on Check Name and confirm your username and password
|
||||
|
||||
Start Microsoft Outlook and enter your username and password. It will
|
||||
start to synchronize your mailbox. This could take a long time if you
|
||||
have many emails, events, tasks and contacts. Once this step is
|
||||
completed, check the autodiscovery service with Outlook 2007 or 2010 by
|
||||
simultaneously holding the CTRL key on your keyboard and right-clicking
|
||||
on the Outlook icon in the notification toolbar. A special entry named
|
||||
"Test E-mail AutoConfiguration..." will appear and will enable you to
|
||||
check the service.
|
||||
|
||||
Known Issues or Limitations
|
||||
---------------------------
|
||||
|
||||
* Make sure you periodically backup all your data regarding SOGo.
|
||||
* Make sure you have no firewalls activated between your Microsoft
|
||||
Outlook clients and the SOGo server with Native Outlook Compatibility
|
||||
module. If you do, use "Outlook Anywhere" to connect Outlook to
|
||||
SOGo/OpenChange.
|
||||
|
||||
Current Limitations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The current version of the Native Microsoft Outlook compatibility layer
|
||||
has some limitations.
|
||||
|
||||
Those limitations will be overcome in the upcoming releases. If you are
|
||||
interested in having those limitations fixed more rapidly, please
|
||||
contact Inverse by sending an email to support@inverse.ca.
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
* If you can't see any email's content with Microsoft Outlook 2007,
|
||||
install the latest Service Pack available from Microsoft's website for
|
||||
this specific version. Microsoft Outlook 2007 (12.0.6423.100) SP2 MSO
|
||||
(12.0.6425.1000) is known to work.
|
||||
* When you create a new Microsoft Outlook profile, not all folders might
|
||||
be synchronized during the first start. Simply select the appropriate
|
||||
folder and click "Send and Receive". Synchronizing a folder may take
|
||||
some time. For example, a folder with 1000 email messages might take
|
||||
around 5 minutes based on the underlying hardware.
|
||||
* Errors when synchronizing the "Offline Address Book" are normal and
|
||||
can be ignored for now. This feature is currently not supported.
|
||||
* If you face strange issues from Microsoft Outlook, you might want to
|
||||
remove any data associated with the user from the SOGo server and
|
||||
recreate a Microsoft Outlook profile.
|
||||
To remove any data associated to a user, use
|
||||
the `openchange_user_cleanup` script distributed with SOGo. The script
|
||||
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
|
||||
RHEL).
|
||||
To reset a user, run the script as root:
|
||||
`python openchange_user_cleanup username`. See the usage output for additional options.
|
||||
* The "Out of Office Assistant" will not currently work. This feature
|
||||
has not been implemented.
|
||||
* Creating folders below INBOX (when not normally permitted by the IMAP
|
||||
server), below the Personal Calendar or Personal Address Book will work
|
||||
in Outlook cached mode but the server-side operation will fail and these
|
||||
folders will never be created. Potentially data loss can occur if the
|
||||
Outlook profile is destroyed. If you wan to create additional top-level
|
||||
mail folders, calendars or address books, open Outlook's folder list,
|
||||
select the top level node (usually, "email@example.com") and choose "New
|
||||
Folder..." from the contextual menu. Choose the relevant item types.
|
||||
|
||||
Mail
|
||||
^^^^
|
||||
|
||||
* Sharing mail folders is not supported.
|
||||
* To avoid possibly lossy conversion from RTF to HTML, Outlook should be
|
||||
configured to send all mails as HTML (or plaintext) instead of _Outlook
|
||||
Rich Text Format_.
|
||||
|
||||
Calendar
|
||||
^^^^^^^^
|
||||
|
||||
* Labels will not work.
|
||||
* It might be impossible to view event details from a shared calendar.
|
||||
This issue is being worked on.
|
||||
|
||||
Tasks
|
||||
^^^^^
|
||||
|
||||
* Tasks with start/due dates created from Outlook might not appear
|
||||
correctly in SOGo due to a timezone issue.
|
||||
* Reminders are not yet supported.
|
||||
* Assigning tasks will not work.
|
||||
|
||||
Contacts
|
||||
^^^^^^^^
|
||||
|
||||
* Categories will not work.
|
||||
* Distribution lists will not work.
|
||||
* Under Microsoft Outlook 2010, the special folder "Suggested Contacts"
|
||||
will not work.
|
||||
* The "Offline Address Book" will not work. This feature is not yet
|
||||
supported.
|
||||
|
||||
Notes
|
||||
^^^^^
|
||||
|
||||
* Notes are not synchronized in any ways with SOGo. The current version
|
||||
of SOGo lacks support for notes.
|
||||
|
||||
If you notice anything else, please send contact Inverse by sending an
|
||||
email to support@inverse.ca.
|
||||
|
||||
include::includes/additional-info.asciidoc[]
|
||||
|
||||
include::includes/commercial-support.asciidoc[]
|
||||
@@ -1,495 +0,0 @@
|
||||
Microsoft Outlook CalDAVSynchronizer Configuration Guide
|
||||
========================================================
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See includes/global-attributes.asciidoc
|
||||
for authors, copyright and license information.
|
||||
|
||||
////
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
This guide will walk you through the installation and configuration of Microsoft Outlook for a better integration with SOGo through the use of the CalDavSynchronizer addon.
|
||||
|
||||
Prior going over this guide, you should have a working SOGo
|
||||
installation. Please refer to the _SOGo Installation and Configuration
|
||||
Guide_ for more information on installing and configuring SOGo.
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available
|
||||
at https://www.sogo.nu/support.html#/documentation.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Outlook CalDav Synchronizer is an open source addon for Microsoft Windows Outlook. It synchronizes events, tasks and contacts between Microsoft Outlook and CalDAV or CardDAV servers. Supported Outlook versions are Outlook 2007 to Outlook 2016.
|
||||
Together with other open source solutions like SOGo, a full open source Microsoft Exchange server replacement for desktop users is finally possible and enterprise ready.
|
||||
Outlook CalDav Synchronizer is Free and Open-Source Software (FOSS) , licensed under AGPL3 and developed by
|
||||
|
||||
* https://sourceforge.net/u/nertsch/profile/[Gerhard Zehetbauer]
|
||||
* https://sourceforge.net/u/nimm/profile/[Alexander Nimmervoll]
|
||||
|
||||
Project Links
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The project source and binaries for installation are hosted on GitHub and SourceForge or can be downloaded from https://caldavsynchronizer.org[caldavsynchronizer.org]
|
||||
|
||||
* https://github.com/aluxnimm/outlookcaldavsynchronizer
|
||||
* https://sourceforge.net/projects/outlookcaldavsynchronizer/
|
||||
|
||||
Social Media
|
||||
~~~~~~~~~~~~
|
||||
|
||||
https://www.facebook.com/caldavsynchronizer/[CalDav Synchronizer on Facebook]
|
||||
|
||||
Enterprise Support
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Alinto (https://alinto.com/[http://alinto.com]) offers professional services around SOGo to help organizations deploy the solution and
|
||||
migrate from their legacy systems.
|
||||
|
||||
For enterprise support on the integration between SOGo and Microsoft Outlook using the Outlook CalDav Synchronizer, please visit https://caldavsynchronizer.org/enterprise
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
The most important features are
|
||||
|
||||
* Open Source, the only free Outlook CalDAV and CardDAV addon
|
||||
* two-way-sync
|
||||
* support for CalDAV calendars and tasks, CardDAV contacts
|
||||
* support for Google native Contacts and Tasks API
|
||||
* full support for timezones and recurring events with exceptions
|
||||
* SSL/TLS support, support for self-signed certificates
|
||||
* proxy support
|
||||
* Autodiscovery of calendars and addressbooks
|
||||
* configurable sync timerange filter
|
||||
* time-triggered-sync and sync changes from Outlook immediately
|
||||
* Category Filtering (sync CalDAV calendar/tasks to Outlook categories)
|
||||
* map CalDAV server colors to Outlook category colors
|
||||
* Use server settings from Outlook IMAP/POP3 account profile
|
||||
* Mapping of Distribution Lists to SOGo VLIST contact groups
|
||||
* Configurable mapping of Outlook custom properties
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Download and extract the `OutlookCalDavSynchronizer-<Version>.zip` into any directory and start setup.exe. You can change the default install path, but you need to use a directory on the `C:\` drive. Follow the instructions and restart Outlook after the installation is finished.
|
||||
|
||||
image::images/installer1.png[scaledwidth="100%",alt="Installer Step 1"]
|
||||
image::images/installer2.png[scaledwidth="100%",alt="Installer Step 2"]
|
||||
|
||||
Next, you will see a ribbon CalDav Synchronizer in Outlook and can add synchronization profiles for you SOGo calendars, addressbooks and tasks.
|
||||
|
||||
image::images/outlook_ribbon.png[scaledwidth="100%",alt="Outlook Ribbon"]
|
||||
|
||||
In the Synchronization profiles dialog, press *Add new profile* if you just need to synchronize one resource or *Add multiple profiles* if you need to synchronize multiple calendars, addressbooks or task folders.
|
||||
|
||||
image::images/add_multiple.png[scaledwidth="75%",alt="Add multiple profiles"]
|
||||
|
||||
Next, select the SOGo profile type
|
||||
|
||||
image::images/select_profiletype.png[scaledwidth="100%",alt="Select Profile type"]
|
||||
|
||||
In the multiple profile setup dialog you can configure the details of the sync profiles.
|
||||
|
||||
image::images/configure_multiple.png[scaledwidth="100%",alt="Multiple Profile Configuration"]
|
||||
|
||||
First, you should change the profile name and configure the server settings, the DAV URL is prefilled with the default SOGo DAV path and you should only change the hostname of your SOGo server, enter Username and Password. If you also have configured an IMAP account and your domain supports autodiscovery using DNS SRV records you can also try to fetch the server settings from your existing mail account in Outlook by pressing *Get IMAP/POP3 account settings*. If successful, username and password will be used from the existing mail account and the DAV URL will be discovered.
|
||||
If all server settings are configured press *Discover resources and assign to Outlook folders* to start the autodiscovery of all server resources.
|
||||
|
||||
You can assign Outlook folders to found calendar, addressbook and task resources in the three tab views.
|
||||
|
||||
image::images/select_calendar.png[scaledwidth="100%",alt="Add calendar resources"]
|
||||
image::images/select_addressbook.png[scaledwidth="100%",alt="Add addressbook resources"]
|
||||
image::images/select_task.png[scaledwidth="100%",alt="Add task resources"]
|
||||
|
||||
To assign a folder click on the "..." button for the corresponding resource and either choose an existing Outlook folder or create a new one in the folder dialog.
|
||||
|
||||
image::images/select_folder.png[scaledwidth="60%",alt="Select Outlook folder"]
|
||||
image::images/new_folder.png[scaledwidth="60%",alt="Add new Outlook folder"]
|
||||
|
||||
If you chose *Add new profile* for only one resource you can also choose the Outlook folder and dependent on the folder type you will create a calendar, addressbook or task profile.
|
||||
|
||||
image::images/profile_config.png[scaledwidth="100%",alt="Single Profile Configuration"]
|
||||
|
||||
If you know the correct calendar CalDAV URL, you can also enter that directly into the DAV Url textbox or paste it from the SOGo Web Frontend, when selecting Link in the calendar properties. For the personal calendar it looks like
|
||||
https://server.example/remote.php/dav/calendars/caldav/personal/
|
||||
|
||||
Furthermore, you can configure sync settings and intervals or keep the default settings which are automatic Two-Way-Sync every 30 minutes for all events from 60 days in the past to 365 days in the future.
|
||||
|
||||
image::images/profile_advanced.png[scaledwidth="100%",alt="Advanced Settings"]
|
||||
|
||||
For addressbooks, the profile setup is similar, just choose an Outlook contacts folder for synchronization.
|
||||
|
||||
If needed, you can configure network and proxy options or special mapping configuration parameters in the corresponding option pages.
|
||||
|
||||
image::images/profile_network.png[scaledwidth="100%",alt="Network settings"]
|
||||
image::images/profile_advanced_event_mapping.png[scaledwidth="100%",alt="Event mapping configuration"]
|
||||
image::images/profile_advanced_contact_mapping.png[scaledwidth="100%",alt="Contact mapping configuration"]
|
||||
image::images/profile_advanced_task_mapping.png[scaledwidth="100%",alt="Task mapping configuration"]
|
||||
image::images/profile_advanced_custom_mapping.png[scaledwidth="100%",alt="Custom mapping configuration"]
|
||||
|
||||
See *Advanced settings* below for a detailed description of all available options.
|
||||
|
||||
After the configuration of the sync profile is finished you can start the synchronization with pressing *Synchronize now* in the CalDav Synchronizer ribbon and your Outlook resources will be in sync with your SOGo resources.
|
||||
|
||||
You can check the status of the last sync runs with the *Status* button in the ribbon.
|
||||
|
||||
image::images/status_report.png[scaledwidth="50%",alt="Status report"]
|
||||
|
||||
Should there be any errors or warnings during synchronization, you can check the *Reports* in the ribbon.
|
||||
|
||||
image::images/sync_report.png[scaledwidth="100%",alt="Sync report"]
|
||||
|
||||
Configuration Options
|
||||
---------------------
|
||||
|
||||
Synchronization Settings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* *Outlook → Server (Replicate):* syncronize everything from Outlook to the server (one way)
|
||||
|
||||
* *Outlook ← Server (Replicate):* synchronize everything from the server to Outlook (one way)
|
||||
|
||||
* *Outlook → Server (Merge):* synchronize everything from Outlook to the server but don’t change events created on the server
|
||||
|
||||
* *Outlook ← Server (Merge):* synchronize everything from the server to Outlook but don’t change events created in Outlook
|
||||
|
||||
* *Outlook ←→ Server (Two-Way):* Two-Way synchronization between Outlook and the server with one of the following conflict resolution
|
||||
|
||||
* *Conflict resolution*
|
||||
(only used in Two-Way synchronization mode and only available in *advanced settings*)
|
||||
|
||||
** *Outlook Wins:* If an event is modified in Outlook and in the server since last snyc, use the Outlook version. If an event is modified in Outlook and deleted in the server since last snyc, also use the Outlook version. If an event is deleted in Outlook and modified in the server, also delete it in the server.
|
||||
|
||||
** *Server Wins:* If an event is modified in Outlook and in the server since last snyc, use the server version. If an event is modified in Outlook and deleted in the server since last snyc, also delete it in Outlook. If an event is deleted in Outlook and modified in the server, recreate it in Outlook.
|
||||
|
||||
** *Automatic:* If event is modified in Outlook and in the server since last snyc, use the last recent modified version. If an event is modified in Outlook and deleted in the server since last snyc, delete it also in Outlook. If an event is deleted in Outlook and modified in the server, also delete it in the server.
|
||||
* *Synchronization interval (minutes):* Choose the interval for synchronization in minutes, if 'Manual only' is choosen, there is no automatic sync but you can use the 'Synchronize now' menu item.
|
||||
|
||||
* *Perform synchronization in chunks* perform CalDAV/CardDAV sync in chunks with configurable chunk size to avoid OutOfMemoryEceptions, enabled by default because of lower memory consumption for huge resources. *(only in advanced settings)*
|
||||
|
||||
* *Use time range filter* *(only in advanced settings)*
|
||||
For performance reasons it is useful to sync only a given timespan of a big calendar, especially past events are normally not necessary to sync after a given timespan. But be aware that Outlook and Google and some other CalDAV servers calculate the intersection with the time-range differently for recurring events which can cause doubled or deleted events, so it is recommended to select a time-range which is larger than the largest interval of your recurring events (e.g. 1 year for birthdays).
|
||||
|
||||
Advanced Settings
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When *Show advanced settings* is enabled, you can expand the tree view of the profile to configure network and proxy options and mapping configuration options.
|
||||
|
||||
Network and Proxy Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here you can configure advanced network options and proxy settings.
|
||||
|
||||
* *Close connection after each request* Don’t use KeepAlive, only useful for servers which don’t support it.
|
||||
|
||||
* *Use Preemptive Authentication* Send Authentication header with each request to avoid 401 responses and resending the request, disable only if the server has problems with preemptive authentication.
|
||||
|
||||
* *Force basic authentication* Set basic authentication headers to avoid problems with negotiation or digest authentication with servers like Apple OS X / macOS. This is only recommended if you use a secure HTTPS connection, otherwise passwords are sent in cleartext.
|
||||
|
||||
* *Use System Default Proxy* Use proxy settings from Internet Explorer or config file, uses default credentials if available for NTLM authentication.
|
||||
|
||||
* *Use manual proxy configuration* Specify proxy URL as `http://<your-proxy-domain>:<your-proxy-port>` and optional Username and Password for Basic Authentication.
|
||||
|
||||
Mapping Configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here you can configure what properties should be synced.
|
||||
|
||||
Event Mapping Configuration
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
For appointments you can choose if you want to map reminders (just upcoming, all or none) and the description body.
|
||||
|
||||
* *Export html description X-ALT-DESC converted from RTF Body* If enabled, convert formatted RTF Body of Outlook appointment to html and export it as X-ALT-DESC property. The RTF to html conversion is experimental, inline images and some formatting properties can’t be converted! Be aware that some servers like Google Calendar drop this attribute!
|
||||
* *Set RTF Body from X-ALT-DESC html description* If enabled, convert X-ALT-DESC description html property to RTF and set Outlook appointment RTF Body. The html to RTF conversion is experimental, not all html formatting options can be converted! This overwrites also the plaintext Body!
|
||||
|
||||
* *Timezone settings* See section Timezone mapping below.
|
||||
|
||||
*Use GlobalAppointmentID for UID attribute:* Use Outlook GlobalAppointmendID instead of random Guid for UID attribute in new CalDAV events. This can avoid duplicate events from invitations.
|
||||
|
||||
* In *Privacy settings* you can configure if you want to map Outlook private appointments to CLASS:CONFIDENTIAL and vice versa. This could be useful for Owncloud for example, if you share your calendar with others and they should see start/end dates of your private appointments. You can also map all CLASS:PUBLIC events to Outlook private appointments.
|
||||
|
||||
* In *Scheduling settings* you can configure if you want to map attendees and organizer and if notifications should be sent by the server.
|
||||
|
||||
* Use *Don’t send appointment notifications* for SOGo servers and *SCHEDULE-AGENT=CLIENT* for other servers if you want to send invitations from Outlook and avoid that the server sends invitations too, but be aware that not all servers (e.g. Google) support the SCHEDULE-AGENT=CLIENT setting.
|
||||
|
||||
* In *Outlook settings* you can also define a filter category so that multiple CalDAV-Calendars can be synchronized into one Outlook calendar via the defined category (see Category Filter and Color below).
|
||||
|
||||
* *Cleanup duplicate events after each sync run:* removes duplicate Outlook appointments based on start,end and subject of the events after each sync run, be aware of possible performance penalties with this option enabled.
|
||||
|
||||
Contact Mapping Configuration
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
* For contacts you can configure if birthdays should be mapped or not. If birthdays are mapped, Outlook also creates an recurring appointment for every contact with a defined birthday.
|
||||
|
||||
* You can also configure if contact photos should be mapped or not. Contact photo mapping from Outlook to the server doesn’t work in Outlook 2007. You can also add an option to not overwrite the contact photo in Outlook when it changes on the server, which could happen due to other mobile clients reducing the resolution for example.
|
||||
|
||||
* Don’t overwrite FileAs in Outlook uses the Outlook settings for FileAs and doesn’t overwrite the contact FileAs with the FN from the server.
|
||||
|
||||
* Fix imported phone number format adds round brackets to the area code of phone numbers, so that Outlook can show correct phone number details with country and area code, e.g. +1 23 45678 is mapped to +1 (23) 45678.
|
||||
|
||||
* Map OutlookEmailAddress1 to WORK instead of HOME, enable when you need to change the order of email address mapping.
|
||||
|
||||
* Write IM addresses as IMPP attributes. If enabled IMPP is used instead of X-AIM,X-ICQ,X-JABBER etc. for writing Instant messenger addresses in vCards. (SOGo is only using X-AIM atm.)
|
||||
|
||||
* Default IM protocol. Choose the default IM service type protocol which will be added to the chat address field from Outlook when writing vCards, defaults to AIM.
|
||||
|
||||
* Map Distribution Lists enables the sync of contact groups / Distribution Lists, right now the DAV contact group format SOGo VLIST or vCards with KIND:group are available, see *Distribution Lists* below.
|
||||
|
||||
Task Mapping Configuration
|
||||
++++++++++++++++++++++++++
|
||||
|
||||
* For tasks (not for Google task profiles) you can configure if you want to map reminders (just upcoming, all or none), the priority of the task, the description body and if recurring tasks should be synchronized.
|
||||
|
||||
* You can also define if task start and due dates should be mapped as floating without timezone to avoid issues with tasks across different timezones.
|
||||
|
||||
* Similar to calendars you can also define a filter category so that multiple CalDAV Tasklists can be synchronized into one Outlook task folder via the defined category.
|
||||
|
||||
Timezone Settings
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Outlook and Windows use different timezone definitions than most CalDAV servers and other clients. When adding new events on the server you have different options how the timezone of the newly created VEVENT is generated. The default setting uses the default Windows timezone from Outlook (e.g. W. Europe Standard Time) or the selected timezones for the start and end of the appointment. Since some servers have problems with that timezone definitions you can change that behaviour in the event mapping configuration with the following options:
|
||||
|
||||
* *Create events on server in UTC* Use UTC instead of Outlook Appointment Timezone for creating events on CalDAV server. Not recommended for general use, because recurrence exceptions over DST changes can’t be mapped and Appointments with different start and end timezones can’t be represented.
|
||||
* *Create events on server in downloaded IANA Timezones* Use IANA instead of Windows Timezones for creating events on CalDAV server. Needed for servers which do not accept non standard Windows Timezones like GMX for example. Timezone definitions will be downloaded from http://tzurl.org.
|
||||
|
||||
* *Use IANA Timezone* Use this IANA timezone for default Outlook/Windows timezone. Manually selected different timezones in Outlook appointments will be mapped to first corresponding IANA timezone.
|
||||
|
||||
* *Include full IANA zone with historical data* Use full IANA timezone definition with historical data. Needs more bandwith and can be incompatible when manually importing in Outlook.
|
||||
|
||||
Custom Properties Mapping
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When you expand the tree view of the profile for events and tasks, you can configure the mapping of custom properties.
|
||||
|
||||
* *Map all Outlook custom properties to X-CALDAVSYNCHRONIZER attributes* If enabled, all Outlook custom text properties of the appointment/task are mapped to DAV attributes with the prefix X-CALDAVSYNCHRONIZER- and vice versa.
|
||||
|
||||
* You can also define manual mapping pairs of Outlook custom attributes and DAV X-Attributes. This will overrule the general mapping of all Outlook custom properties if both is activated. Outlook properties that don’t exist, will be created. DAV properties MUST start with X-. Only Outlook custom properties of type Text can be mapped.
|
||||
|
||||
Managing Meetings and Invites
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Outlook can only track meeting responses and invites in the main calender folder. If you schedule meetings from Outlook which are synced with the CalDAV server you have two possibilities to avoid double invitation mails for all attendees. First, you can enable the option *Don’t send appointment notifications (enabled by default for SOGo profiles)* or *SCHEDULE-AGENT=CLIENT* (for other servers) and let only Outlook send the meeting invites, if the server supports this option. Or you can disable this option and let the server schedule the meetings after syncing the meeting. Then you need to disable the invitation mails sent from Outlook. This is possible by unchecking the checkbox left to the attendee name in the meeting planning dialog. When syncing meetings created in Outlook to the server, the option *Use GlobalAppointmentID for UID attribute* is recommended. This can avoid duplicate events from invitations.
|
||||
|
||||
The response status of all attendees can be synced from Outlook to the server but only the status of the own Outlook identity (if included in the attendees) can be synced from the server to Outlook due to limitations of the Outlook Object Model.
|
||||
|
||||
When receiving invites from the CalDAV server and via Email in your INBOX, Outlook will automatically create a tentative meeting in the main calendar folder
|
||||
|
||||
To avoid double meetings the option *Cleanup duplicate events after each sync run* in event mapping configuration is recommended.
|
||||
|
||||
Free/busy Lookups
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can configure free/busy lookups globally in the Outlook options.
|
||||
|
||||
Select Options/Calendar and there free/busy information and use a free/busy URL of your server with placeholder like %Name%, e.g. http://myserver/freebusy.php/%Name%
|
||||
|
||||
For SOGo the URL looks like: http://<hostname>/SOGo/dav/public/%NAME%/freebusy.ifb
|
||||
|
||||
And `SOGoEnablePublicAccess` must be set to `YES`
|
||||
|
||||
Then every attendee in the Outlook planning view gets resolved with that URL for a free/busy lookup against your server.
|
||||
|
||||
Scheduling Settings and Resources
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If your server supports resources (for SOGo see http://wiki.sogo.nu/ResourceConfiguration disable *set SCHEDULE-AGENT=CLIENT* in Mapping Configuration, so that the server can handle the resource invitation mails, add the resource email adress as attendee in the Outlook appointment and choose type ressource (house icon) for it.
|
||||
|
||||
Category Filter and Color
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to sync multiple CalDAV calendars or task lists into one Outlook folder you can configure an Outlook category for filtering in the *Mapping Configuration*. You can choose a category from the dropdown list of all available Outlook categories or enter a new category name.
|
||||
|
||||
For all events/tasks from the server the defined category is added in Outlook, when syncing back from Outlook to the server only appointments/tasks with that category are considered but the filter category is removed. The category name must not contain any commas or semicolons!
|
||||
|
||||
With the checkbox *Sync also Appointments without any category* also all appointments/tasks without a category are synced to the server.
|
||||
|
||||
With the checkbox below you can alternatively negate the filter and sync all appointments/tasks except this category.
|
||||
|
||||
For calendars it is also possible to choose the color of the category or to fetch the calendar color from the server and map it to the nearest supported Outlook category color with the button *Fetch Color*. With *Set DAV Color* it is also possible to sync the choosen category color back to set the server calendar color accordingly. With *Category Shortcut Key* you can define the shortcut key of the selected category for easier access when creating appointments.
|
||||
|
||||
Reminders
|
||||
~~~~~~~~~
|
||||
|
||||
In event and task mapping configuration you can define if you want to map (all/non/just upcoming) reminders. If you get the following error message when trying to set reminders in Outlook
|
||||
|
||||
`The reminder will not appear because the item is in a folder that doesn’t support reminders.`
|
||||
|
||||
you can try to change the Outlook options as discussed in
|
||||
|
||||
http://answers.microsoft.com/en-us/office/forum/office_2016-outlook/outlook-2016-calendar-reminders/8f40bcdd-e3fc-4f29-acaf-544f48d63992
|
||||
|
||||
or try the following reported by user __Todo18__
|
||||
|
||||
1. Create a new storage folder in Outlook via the File menu, Info, Account Settings. In the Data Files tab, you can Add a new (.pst) data file. After the file has been added, Make it the default [data file], and close the dialog.
|
||||
|
||||
2. Go to the Calendar window, right click on the calendar that’s giving you problems, and select Move Calendar. In the dialog, pick the data file that you created in the first step, and confirm. Don’t forget to update the storage folder in the CalDav Synchronizer settings!
|
||||
|
||||
Distribution Lists
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When enabled in Contact Mapping configuration you can now also sync Outlook Distribution Lists with your server contact groups. Since different servers use different formats to store contact groups, you will be able to choose the used DAV contact group format. Right now, the VLIST format for SOGo servers and vCards with KIND:group are supported. Don’t enable any of these options when your server doesn’t support it!
|
||||
|
||||
Since Outlook Distribution Lists also support list members which aren’t in the addressbook but SOGo VLISTs don’t, we add them as custom X-Attributes. With this workaround those members aren’t displayed in SOGo but won’t get lost when syncing back to Outlook.
|
||||
|
||||
Since vCard in version 3.0 doesn’t support contact groups we use X-ADDRESSBOOK-SERVER attributes for KIND and MEMBER for contact groups.
|
||||
|
||||
General Options and SSL settings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the General Options Dialog you can change settings which are used for all synchronization profiles.
|
||||
|
||||
* *Automatically check for newer versions* set to false to disable checking for updates.
|
||||
* *Check Internet connection before sync run* checks if an interface is up and try DNS query to dns.msftncsi.com first and if that fails try to download http://www.msftncsi.com/ncsi.txt with the configured proxy before each sync run to avoid error reports if network is unavailable after hibernate for example. Disable this option if you are in a local network where DNS and that URL is blocked.
|
||||
|
||||
* *Store data in roaming folder* set to true if you need to store state and profile data in the AppData\Roaming\ directory for roaming profiles in a AD domain for example. When changing this option, a restart of Outlook is required.
|
||||
|
||||
* *Include custom message classes in Outlook filter* Disabled by default, enable only if you have custom forms with message_classes other than the default IPM.Appointment/Contact/Task. For better performance, Windows Search Service shouldn’t be deactivated if this option is enabled.
|
||||
|
||||
* *Use fast queries for Outlook folders* Enabled by default, uses fast GetTable queries when accessing Outlook folders. Disable only if you get errors in GetVersions, when disabled every item needs to be requested which causes a performance penalty!
|
||||
|
||||
* *Trigger sync after Outlook Send/Receive and on Startup* If checked a manual sync is triggered after the Outlook Send/Receive finishes and on Outlook startup.
|
||||
|
||||
* *Show advanced settings as default* Show the advanced settings in synchronization profiles as default if enabled.
|
||||
|
||||
* *Expand all nodes in Synchronization profiles* Enabled by default, expands all nodes in the synchronization profiles to see the suboptions for network settings and mapping configuration.
|
||||
|
||||
* *Enable Tray Icon* Enabled by default, you can disable the tray icon in the Windows Taskbar if you don’t need it.
|
||||
|
||||
* *Fix invalid settings* Fixes invalid settings automatically, when synchronization profiles are edited.
|
||||
|
||||
* *Show Sync Progress Bar* and *Sync Progress Bar Threshold (Items)* Enabled by default, show a progress bar if more than the treshold of items need to be loaded during a synchronization run. If disabled, no progress bar is shown but be aware that for larger changes Outlook can freeze, since some operations need to be performed in the Outlook main thread.
|
||||
|
||||
* *Accept invalid chars in server response* If checked invalid characters in XML server responses are allowed. A typical invalid char, sent by some servers is Form feed (0x0C).
|
||||
|
||||
* * Enable useUnsafeHeaderParsing* Enable, if the server sends invalid http headers, see common network errors. Needed for Yahoo and cPanel Horde servers for example. The general option overrides the setting in the app.config file.
|
||||
|
||||
* *CalDav Connection Timeout (secs)* For slow server connections you can increaste the timeout value (default 90 secs).
|
||||
|
||||
SSL/TLS settings
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have problems with SSL/TLS and self-signed certificates, you can change the following settings at your own risk.
|
||||
|
||||
The recommended way would be to add the self signed cert to the Local Computer Trusted Root Certification Authorities
|
||||
|
||||
You can import the cert by running the MMC as Administrator.
|
||||
|
||||
* *Disable Certificate Validation* set to true to disable SSL/TLS certificate validation, major security risk, use with caution!
|
||||
|
||||
* *Enable Client Certificates* If enabled, the available client certificates from the Windows user certificate store will automatically be provided.
|
||||
|
||||
* *Enable Tls12* set to false to disable TLS12, not recommended!
|
||||
|
||||
* *Enable Ssl3* set to true to enable deprecated SSLv3, major security risk, use with caution!
|
||||
|
||||
Logging
|
||||
^^^^^^^
|
||||
|
||||
In the *General Logging* section you can show or clear the log file and define the log level. Possible log levels are `INFO` and `DEBUG`.
|
||||
|
||||
You can also configure Synchronization reports for all profiles, this can be configured via general Options:
|
||||
|
||||
* *Log* You can choose if you want to generate reports for *"Only sync runs with errors"* or *"Sync runs with errors or warnings"* or *"All sync runs"*.
|
||||
|
||||
* *Show immediately* configures if the Sync reports should be shown immediately after a sync run with errors, with warnings or errors, or not at all.
|
||||
|
||||
* *Delete reports older than (days)* Automatically delete reports which are older than the days configured.
|
||||
|
||||
You can show reports manually with the *Reports* button in the CalDav Synchronizer Ribbon. There you can choose from available reports (shown as profile name with timestamp of the sync run) and see informations about items synced and if there were any warnings or errors. You can also delete reports or add them to a zip file via the context menu. If the last sync run lead to any errors, a warning symbol is shown in the Ribbon or the Report window opens if configured in the general options.
|
||||
|
||||
Profile Import/Export
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the toolbar of the synchronization profiles you can export all profiles to a file and import profiles from an earlier exported file. When exporting, you can choose a filename, the extension is *.cdsp and all options are saved in an xml format into this file. When importing the file, existing profiles are merged with the imported ones. If the selected Outlook folder for the profile doesn’t exist during import, you need to manually select a folder before you can save the options, they are not automatically created. You need also be aware of the fact, that saved profile passwords won’t work on other accounts or machines, since the encryption is dependant on the current user. But you can use the account password from the IMAP/POP3 account if available. General options are not saved in that file, but in the registry in `HKEY_CURRENT_USER\Software\CalDavSynchronizer`.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Synchronization Status
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
With the *Status* button in the CalDav Synchronizer Ribbon or via doubleclick from the TrayIcon you can access the status of the active sync profiles with their last sync run shown in minutes ago and the status OK, error, or warning. When clicking on the profile name you get to the according sync profile settings, when clicking the status icon, you can open the according sync report. When a sync run has any errors or warnings you will get a notification from the CalDav Synchronizer TrayIcon.
|
||||
|
||||
Debugging
|
||||
~~~~~~~~~
|
||||
|
||||
Options and state information is normally stored in the following folder:
|
||||
|
||||
----
|
||||
C:\Users\<Your Username>\AppData\Local\CalDavSychronizer
|
||||
----
|
||||
|
||||
If you activated Store data in roaming folder the location is changed to the following folder:
|
||||
|
||||
----
|
||||
C:\Users\<Your Username>\AppData\Roaming\CalDavSychronizer
|
||||
----
|
||||
|
||||
There is one `options_<your outlook profile>.xml` file which stores the options for each outlook profile.
|
||||
|
||||
For each sync profile there is a subfolder with state information stored in a relations.xml file after the inital sync. If you delete that folder, a fresh inital sync is performed. In the Synchronization profiles dialog a context menu is available in each profile (right click), which allows to open the cache directory and read the relations.xml file.
|
||||
|
||||
Each synchronization attempt is logged in the `log.txt` file. There you can find information about sync duration and the amount of added, deleted or modified events. Errors and Exceptions are logged aswell. You can view and clear the log file in *General Options*. There you can also change the log level from `INFO` to `DEBUG`.
|
||||
|
||||
In the install dir (The default is `C:\Program Files (x86)\CalDavSynchronizer`) you will find the app config file
|
||||
` CalDavSynchronizer.dll.config`
|
||||
|
||||
In that xml file you can config timeout parameters and config options in the section `appSettings`
|
||||
|
||||
After changing parameters you have to restart Outlook.
|
||||
|
||||
* *wpfRenderModeSoftwareOnly*: When set to true, turn off hardware acceleration and use Software Rendering only. Useful if you have issues with WPF and your graphics card driver.
|
||||
|
||||
You can also change defaults for some of the general options like CheckForNewVersions, StoreAppDatainRoamingFolder, IncludeCustomMessageClasses and SSL/TLS options, useful for All Users deployment, because general options are stored per user in the HKCU registry hive.
|
||||
|
||||
In the section `system.net` you can define proxy settings, e.g. use of NTLM credentials
|
||||
|
||||
----
|
||||
<defaultProxy useDefaultCredentials="true">
|
||||
</defaultProxy>
|
||||
----
|
||||
|
||||
In this section you can also allow UnsafeHeaderParsing if the server sends invalid http headers.
|
||||
|
||||
----
|
||||
<system.net>
|
||||
<settings>
|
||||
<servicePointManager expect100Continue="false" />
|
||||
<httpWebRequest useUnsafeHeaderParsing="true" />
|
||||
</settings>
|
||||
</system.net>
|
||||
----
|
||||
|
||||
This setting can also be enabled in the general options, starting with version 2.10.0.
|
||||
|
||||
In the section `log4net` you can define the log level for the main log (also possible in general options now).
|
||||
level value can be DEBUG or INFO, e.g.:
|
||||
|
||||
----
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="MainLogAppender" />
|
||||
</root>
|
||||
----
|
||||
|
||||
Common network errors
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* System.Net.Http.HttpRequestException: Response status code does not indicate success: '401' ('Unauthorized').
|
||||
** Wrong Username and/or Password provided.
|
||||
|
||||
* System.Net.Http.HttpRequestException: An error occurred while sending the request. --→ System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
|
||||
** The server has KeepAlive disabled. Use *"Close connection after each request"* in *Network and proxy options*.
|
||||
|
||||
* System.Net.Http.HttpRequestException: An error occurred while sending the request. --→ System.Net.WebException: The server committed a protocol violation. Section=ResponseStatusLine
|
||||
** The server sends invalid headers. Enable the general option *Enable useUnsafeHeaderParsing* or the commented out option *useUnsafeHeaderparsing* in the app config file.
|
||||
@@ -1,323 +0,0 @@
|
||||
#
|
||||
# https://github.com/asciidoctor/asciidoctor-pdf/blob/master/docs/theming-guide.adoc
|
||||
#
|
||||
|
||||
font:
|
||||
catalog:
|
||||
# Noto Serif supports Latin, Latin-1 Supplement, Latin Extended-A, Greek, Cyrillic, Vietnamese & an assortment of symbols
|
||||
#Noto Serif:
|
||||
# normal: notoserif-regular-subset.ttf
|
||||
# bold: notoserif-bold-subset.ttf
|
||||
# italic: notoserif-italic-subset.ttf
|
||||
# bold_italic: notoserif-bold_italic-subset.ttf
|
||||
Lato-Light:
|
||||
normal: lato/Lato-Light.ttf
|
||||
bold: lato/Lato-Regular.ttf
|
||||
italic: lato/Lato-LightItalic.ttf
|
||||
bold_italic: lato/Lato-Italic.ttf
|
||||
# M+ 1mn supports ASCII and the circled numbers used for conums
|
||||
#M+ 1mn:
|
||||
# normal: mplus1mn-regular-subset.ttf
|
||||
# bold: mplus1mn-bold-subset.ttf
|
||||
# italic: mplus1mn-italic-subset.ttf
|
||||
# bold_italic: mplus1mn-bold_italic-subset.ttf
|
||||
Inconsolata:
|
||||
normal: inconsolata.ttf
|
||||
bold: inconsolata.ttf
|
||||
italic: inconsolata.ttf
|
||||
bold_italic: inconsolata.ttf
|
||||
page:
|
||||
background_color: FFFFFF
|
||||
layout: portrait
|
||||
initial_zoom: FitH
|
||||
margin: [1in, 1in, 1in, 1in]
|
||||
# margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress
|
||||
margin_inner: 1in
|
||||
margin_outer: 1in
|
||||
size: Letter
|
||||
base:
|
||||
align: justify
|
||||
# color as hex string (leading # is optional)
|
||||
font_color: 333333
|
||||
font_color: 000000
|
||||
# color as RGB array
|
||||
#font_color: [51, 51, 51]
|
||||
# color as CMYK array (approximated)
|
||||
#font_color: [0, 0, 0, 0.92]
|
||||
#font_color: [0, 0, 0, 92%]
|
||||
font_family: Lato-Light
|
||||
# choose one of these font_size/line_height_length combinations
|
||||
#font_size: 14
|
||||
#line_height_length: 20
|
||||
#font_size: 11.25
|
||||
#line_height_length: 18
|
||||
#font_size: 11.2
|
||||
#line_height_length: 16
|
||||
font_size: 10
|
||||
#line_height_length: 15
|
||||
# correct line height for Noto Serif metrics
|
||||
line_height_length: 10
|
||||
#font_size: 11.25
|
||||
#line_height_length: 18
|
||||
line_height: $base_line_height_length / $base_font_size
|
||||
font_size_large: round($base_font_size * 1.25)
|
||||
font_size_small: round($base_font_size * 0.85)
|
||||
font_size_min: $base_font_size * 0.75
|
||||
font_style: normal
|
||||
border_color: EEEEEE
|
||||
border_radius: 4
|
||||
border_width: 0.5
|
||||
section:
|
||||
indent: [0.67in, 0]
|
||||
role:
|
||||
line-through:
|
||||
text_decoration: line-through
|
||||
underline:
|
||||
text_decoration: underline
|
||||
big:
|
||||
font_size: $base_font_size_large
|
||||
small:
|
||||
font_size: $base_font_size_small
|
||||
subtitle:
|
||||
font_size: 0.8em
|
||||
font_color: 999999
|
||||
# FIXME vertical_rhythm is weird; we should think in terms of ems
|
||||
#vertical_rhythm: $base_line_height_length * 2 / 3
|
||||
# correct line height for Noto Serif metrics (comes with built-in line height)
|
||||
vertical_rhythm: $base_line_height_length
|
||||
horizontal_rhythm: $base_line_height_length
|
||||
# QUESTION should vertical_spacing be block_spacing instead?
|
||||
vertical_spacing: $vertical_rhythm
|
||||
link:
|
||||
font_color: 428BCA
|
||||
font_color: 007BFF
|
||||
# literal is currently used for inline monospaced in prose and table cells
|
||||
literal:
|
||||
font_color: 333333
|
||||
font_color: B12146
|
||||
font_color: E83E8C
|
||||
font_family: Inconsolata
|
||||
button:
|
||||
content: "[\u2009%s\u2009]"
|
||||
font_style: bold
|
||||
key:
|
||||
background_color: F5F5F5
|
||||
background_color: F8F8F8
|
||||
border_color: CCCCCC
|
||||
border_offset: 2
|
||||
border_radius: 2
|
||||
border_width: 0.5
|
||||
font_family: $literal_font_family
|
||||
separator: "\u202f+\u202f"
|
||||
mark:
|
||||
background_color: FFFF00
|
||||
border_offset: 1
|
||||
menu:
|
||||
caret_content: " <font size=\"1.15em\"><color rgb=\"b12146\">\u203a</color></font> "
|
||||
heading:
|
||||
align: left
|
||||
font_color: $base_font_color
|
||||
font_style: bold
|
||||
# h1 is used for part titles (book doctype) or the doctitle (article doctype)
|
||||
h1_font_size: floor($base_font_size * 2.6)
|
||||
# h2 is used for chapter titles (book doctype only)
|
||||
h2_font_size: floor($base_font_size * 2.15)
|
||||
h3_font_size: round($base_font_size * 1.7)
|
||||
h4_font_size: $base_font_size_large
|
||||
h5_font_size: $base_font_size
|
||||
h6_font_size: $base_font_size_small
|
||||
#line_height: 1.4
|
||||
# correct line height for Noto Serif metrics (comes with built-in line height)
|
||||
line_height: 1
|
||||
margin_top: $vertical_rhythm * 0.4
|
||||
margin_bottom: $vertical_rhythm * 0.9
|
||||
min_height_after: $base_line_height_length * 1.5
|
||||
h2-margin_bottom: 60
|
||||
#h2-text_decoration: underline
|
||||
title_page:
|
||||
align: right
|
||||
logo:
|
||||
top: 10%
|
||||
title:
|
||||
top: 55%
|
||||
font_size: $heading_h1_font_size
|
||||
font_color: 999999
|
||||
font_color: $base_font_color
|
||||
line_height: 0.9
|
||||
subtitle:
|
||||
font_size: $heading_h3_font_size
|
||||
font_style: bold_italic
|
||||
line_height: 1
|
||||
authors:
|
||||
margin_top: $base_font_size * 1.25
|
||||
font_size: $base_font_size_large
|
||||
font_color: 181818
|
||||
revision:
|
||||
margin_top: $base_font_size * 1.25
|
||||
block:
|
||||
margin_top: 0
|
||||
margin_bottom: $vertical_rhythm
|
||||
caption:
|
||||
align: left
|
||||
font_size: $base_font_size * 0.95
|
||||
font_style: italic
|
||||
# FIXME perhaps set line_height instead of / in addition to margins?
|
||||
margin_inside: $vertical_rhythm / 3
|
||||
#margin_inside: $vertical_rhythm / 4
|
||||
margin_outside: 0
|
||||
lead:
|
||||
font_size: $base_font_size_large
|
||||
line_height: 1.4
|
||||
abstract:
|
||||
font_color: 5C6266
|
||||
font_size: $lead_font_size
|
||||
line_height: $lead_line_height
|
||||
font_style: italic
|
||||
first_line_font_style: bold
|
||||
title:
|
||||
align: center
|
||||
font_color: $heading_font_color
|
||||
font_size: $heading_h4_font_size
|
||||
font_style: $heading_font_style
|
||||
admonition:
|
||||
column_rule_color: $base_border_color
|
||||
column_rule_width: $base_border_width
|
||||
padding: [0, $horizontal_rhythm, 0, $horizontal_rhythm]
|
||||
# icon:
|
||||
# caution:
|
||||
# name: far-lightbulb
|
||||
# name: fa-fire
|
||||
# stroke_color: 111111
|
||||
# size: 24
|
||||
label:
|
||||
text_transform: uppercase
|
||||
font_style: bold
|
||||
# caution:
|
||||
# font_color: F77D05
|
||||
blockquote:
|
||||
font_size: $base_font_size_large
|
||||
border_color: $base_border_color
|
||||
border_width: 0
|
||||
border_left_width: 5
|
||||
# FIXME disable negative padding bottom once margin collapsing is implemented
|
||||
padding: [0, $horizontal_rhythm, $block_margin_bottom * -0.75, $horizontal_rhythm + $blockquote_border_left_width / 2]
|
||||
cite_font_size: $base_font_size_small
|
||||
cite_font_color: 999999
|
||||
verse:
|
||||
font_size: $blockquote_font_size
|
||||
border_color: $blockquote_border_color
|
||||
border_width: $blockquote_border_width
|
||||
border_left_width: $blockquote_border_left_width
|
||||
padding: $blockquote_padding
|
||||
cite_font_size: $blockquote_cite_font_size
|
||||
cite_font_color: $blockquote_cite_font_color
|
||||
# code is used for source blocks (perhaps change to source or listing?)
|
||||
code:
|
||||
font_color: $base_font_color
|
||||
#font_color: FFFFFF
|
||||
font_family: $literal_font_family
|
||||
font_size: ceil($base_font_size)
|
||||
padding: $code_font_size
|
||||
line_height: 1.25
|
||||
# line_gap is an experimental property to control how a background color is applied to an inline block element
|
||||
line_gap: 3.8
|
||||
background_color: F5F5F5
|
||||
background_color: F8F8F8
|
||||
#background_color: 6C757D
|
||||
border_color: CCCCCC
|
||||
border_radius: $base_border_radius
|
||||
border_radius: 0
|
||||
border_width: 0.75
|
||||
border_width: 0
|
||||
conum:
|
||||
font_family: $literal_font_family
|
||||
font_color: $literal_font_color
|
||||
font_size: $base_font_size
|
||||
line_height: 4 / 3
|
||||
glyphs: circled
|
||||
example:
|
||||
border_color: $base_border_color
|
||||
border_radius: $base_border_radius
|
||||
border_width: 0.75
|
||||
background_color: $page-background-color
|
||||
# FIXME reenable padding bottom once margin collapsing is implemented
|
||||
padding: [$vertical_rhythm, $horizontal_rhythm, 0, $horizontal_rhythm]
|
||||
image:
|
||||
align: left
|
||||
prose:
|
||||
margin_top: $block_margin_top
|
||||
margin_bottom: $block_margin_bottom
|
||||
sidebar:
|
||||
background_color: EEEEEE
|
||||
border_color: E1E1E1
|
||||
border_radius: $base_border_radius
|
||||
border_width: $base_border_width
|
||||
# FIXME reenable padding bottom once margin collapsing is implemented
|
||||
padding: [$vertical_rhythm, $vertical_rhythm * 1.25, 0, $vertical_rhythm * 1.25]
|
||||
title:
|
||||
align: center
|
||||
font_color: $heading_font_color
|
||||
font_size: $heading_h4_font_size
|
||||
font_style: $heading_font_style
|
||||
thematic_break:
|
||||
border_color: $base_border_color
|
||||
border_style: solid
|
||||
border_width: $base_border_width
|
||||
margin_top: $vertical_rhythm * 0.5
|
||||
margin_bottom: $vertical_rhythm * 1.5
|
||||
description_list:
|
||||
term_font_style: bold
|
||||
term_spacing: $vertical_rhythm / 4
|
||||
description_indent: $horizontal_rhythm * 1.25
|
||||
outline_list:
|
||||
indent: $horizontal_rhythm * 1.5
|
||||
#marker_font_color: 404040
|
||||
# NOTE outline_list_item_spacing applies to list items that do not have complex content
|
||||
item_spacing: $vertical_rhythm / 2
|
||||
table:
|
||||
background_color: $page_background_color
|
||||
border_color: DDDDDD
|
||||
border_width: $base_border_width
|
||||
cell_padding: 3
|
||||
head:
|
||||
font_style: bold
|
||||
border_bottom_width: $base_border_width * 2.5
|
||||
body:
|
||||
stripe_background_color: F9F9F9
|
||||
foot:
|
||||
background_color: F0F0F0
|
||||
toc:
|
||||
indent: $horizontal_rhythm
|
||||
line_height: $base_line_height
|
||||
dot_leader:
|
||||
#content: ". "
|
||||
font_color: A9A9A9
|
||||
#levels: 2 3
|
||||
footnotes:
|
||||
font_size: round($base_font_size * 0.75)
|
||||
item_spacing: $outline_list_item_spacing / 2
|
||||
header:
|
||||
# Can't show chapter number. See https://github.com/asciidoctor/asciidoctor-pdf/issues/1373
|
||||
font_size: $base_font_size_small
|
||||
line_height: 1
|
||||
vertical_align: middle
|
||||
footer:
|
||||
font_size: $base_font_size_small
|
||||
# NOTE if background_color is set, background and border will span width of page
|
||||
#border_color: DDDDDD
|
||||
border_width: 0.25
|
||||
#height: $base_line_height_length * 2.5
|
||||
height: $base_line_height_length * 5
|
||||
line_height: 1
|
||||
padding: [$base_line_height_length / 2, 1, 0, 1]
|
||||
vertical_align: top
|
||||
recto: &shared_footer
|
||||
#columns: "<50% =0% >50%"
|
||||
left:
|
||||
content: 'Copyright © Inverse inc.'
|
||||
center:
|
||||
content: '{chapter-title}'
|
||||
right:
|
||||
content: '{page-number}'
|
||||
verso: *shared_footer
|
||||
#columns: $footer_recto_columns
|
||||
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# fop fix to build our documentation on CentOS 6
|
||||
#
|
||||
# Inverse inc. <info@inverse.ca>
|
||||
#
|
||||
--- /usr/bin/fop.orig 2012-01-17 21:25:50.000000000 -0500
|
||||
+++ /usr/bin/fop 2012-01-17 21:26:04.000000000 -0500
|
||||
@@ -26,7 +26,7 @@
|
||||
# Set parameters
|
||||
set_jvm
|
||||
set_classpath commons-io batik-all avalon-framework xmlgraphics-commons \
|
||||
- commons-logging fop
|
||||
+ commons-logging fop xalan-j2
|
||||
set_flags $BASE_FLAGS
|
||||
set_options $BASE_OPTIONS
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# xmlgraphics-fop fix to build our documentation on CentOS 5
|
||||
# taken from https://build.opensuse.org/request/show/68994
|
||||
#
|
||||
# Inverse inc. <info@inverse.ca>
|
||||
#
|
||||
--- /usr/bin/xmlgraphics-fop.orig 2012-01-17 18:42:08.000000000 -0500
|
||||
+++ /usr/bin/xmlgraphics-fop 2012-01-17 18:42:18.000000000 -0500
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
# Rest of the configuration
|
||||
MAIN_CLASS=org.apache.fop.cli.Main
|
||||
-BASE_JARS="xmlgraphics-fop xmlgraphics-batik/util xml-commons-jaxp-1.3-apis excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
|
||||
+BASE_JARS="xmlgraphics-fop batik-all xml-commons-jaxp-1.3-apis excalibur/avalon-framework-impl excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
|
||||
|
||||
# Set parameters
|
||||
set_jvm
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
version="1.0">
|
||||
|
||||
<!-- ********************************************************************
|
||||
|
||||
Header / Footer customizations
|
||||
|
||||
This file is part of the SOGo project.
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2011-2014 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
******************************************************************** -->
|
||||
|
||||
<!--
|
||||
Here we are re-defining docbook-xsl/fo/pagesetup.xsl to fit our needs.
|
||||
- top: chapter number on the left
|
||||
- bottom: copyright, chapter name, page
|
||||
-->
|
||||
|
||||
<xsl:param name="header.rule" select="0"/>
|
||||
|
||||
<xsl:template name="header.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<fo:block>
|
||||
<!-- sequence can be odd, even, first, blank -->
|
||||
<!-- position can be left, center, right -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence = 'blank'">
|
||||
<!-- nothing -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='left'">
|
||||
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
|
||||
<xsl:call-template name="gentext">
|
||||
<xsl:with-param name="key" select="'chapter'"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="gentext.space"/>
|
||||
<xsl:number count="chapter" from="book" level="any"/>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
|
||||
<!-- draft -->
|
||||
<xsl:when test="$position='right'">
|
||||
<xsl:call-template name="draft.text"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:param name="footer.rule" select="0"/>
|
||||
<xsl:template name="footer.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<fo:block>
|
||||
<!-- pageclass can be front, body, back -->
|
||||
<!-- sequence can be odd, even, first, blank -->
|
||||
<!-- position can be left, center, right -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$pageclass = 'titlepage'">
|
||||
<!-- nop; no footer on title pages -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'">
|
||||
<xsl:apply-templates select="//copyright[1]" mode="titlepage.mode"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='center'">
|
||||
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
|
||||
<xsl:apply-templates select="." mode="titleabbrev.markup"/>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<!-- nop -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
||||
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
|
||||
@@ -0,0 +1,182 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
version="1.0">
|
||||
|
||||
<!-- ********************************************************************
|
||||
|
||||
SOGo Documentation Docbook FO Parameters
|
||||
|
||||
This file is part of the SOGo project.
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2011-2014 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
******************************************************************** -->
|
||||
|
||||
<!--
|
||||
Global Tasks
|
||||
|
||||
TODO prettier revhistory
|
||||
TODO prettier Table of Contents
|
||||
TODO generate PDF table of contents (like OSX's Preview shows on the right hand side)
|
||||
TODO title 2
|
||||
- align with text?
|
||||
- more above whitespace
|
||||
TODO change the bullet for a prettier one
|
||||
TODO title 3 and 4
|
||||
- align with text?
|
||||
- should be easier to differentiate (check network guide)
|
||||
TODO icon on line wrap in monospace boxes
|
||||
TODO caution, notes, warnings, etc.
|
||||
- box around it
|
||||
- sexy icon
|
||||
TODO -> is converted into an arrow but it's not pretty (is it font or docbook-thingy?)
|
||||
|
||||
-->
|
||||
|
||||
<!--
|
||||
Load default values
|
||||
|
||||
Real upstream schema is at:
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
|
||||
|
||||
but we decided to load all sensible local xsd since it only produce a warning on missing imports.
|
||||
-->
|
||||
<!-- CentOS / RHEL -->
|
||||
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
|
||||
<!-- Debian / Ubuntu -->
|
||||
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
|
||||
<!-- OSX through mac ports -->
|
||||
<xsl:import href="/opt/local/share/xsl/docbook-xsl/fo/docbook.xsl"/>
|
||||
|
||||
<!-- title page extra styling -->
|
||||
<xsl:import href="titlepage-fo.xsl"/>
|
||||
|
||||
<!-- header / footer extra styling -->
|
||||
<xsl:import href="headerfooter-fo.xsl"/>
|
||||
|
||||
<!-- attaching an image to the verso legalnotice component -->
|
||||
<xsl:template match="legalnotice" mode="book.titlepage.verso.mode">
|
||||
<xsl:apply-templates mode="titlepage.mode"/>
|
||||
<fo:block text-align="right">
|
||||
<fo:external-graphic src="url('images/inverse-logo.jpg')" width="3in" content-width="scale-to-fit"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- stylesheet options -->
|
||||
<xsl:param name="title.font.family">Lato-Medium</xsl:param>
|
||||
<xsl:param name="chapter.autolabel" select="0"/>
|
||||
<xsl:attribute-set name="component.title.properties">
|
||||
<xsl:attribute name="padding-bottom">2.5em</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">solid 2px</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="border-bottom">solid 1px</xsl:attribute>
|
||||
<xsl:attribute name="margin-top">2em</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- titles spacing -->
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="margin-top">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- default fonts -->
|
||||
<xsl:param name="body.font.family">Lato-Light</xsl:param>
|
||||
<xsl:param name="body.font.master">10</xsl:param>
|
||||
<xsl:param name="monospace.font.family">Incosolata</xsl:param>
|
||||
|
||||
<!-- revision table layout -->
|
||||
<xsl:attribute-set name="revhistory.title.properties">
|
||||
<xsl:attribute name="font-size">12pt</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="text-align">center</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="revhistory.table.properties">
|
||||
<xsl:attribute name="break-before">page</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="revhistory.table.cell.properties">
|
||||
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Table Of Contents (TOC) options -->
|
||||
<!-- We only want 2 level of ToC depth -->
|
||||
<xsl:param name="toc.section.depth" select="1"/>
|
||||
|
||||
<!-- titles left margin -->
|
||||
<xsl:attribute-set name="section.title.properties">
|
||||
<xsl:attribute name="start-indent"><xsl:value-of select="$body.start.indent"/></xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- lists type -->
|
||||
<xsl:template name="itemizedlist.label.markup">
|
||||
<xsl:param name="itemsymbol" select="'square'"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$itemsymbol='square'"><fo:inline font-family="Lato-Light">▪</fo:inline></xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
<xsl:template name="next.itemsymbol">
|
||||
<xsl:param name="itemsymbol" select="'default'"/>
|
||||
<xsl:choose>
|
||||
<xsl:otherwise>square</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!-- admonition -->
|
||||
<xsl:param name="admon.graphics" select="1"></xsl:param>
|
||||
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
||||
<xsl:param name="admon.graphics.extension">.png</xsl:param>
|
||||
<xsl:attribute-set name="graphical.admonition.properties">
|
||||
<xsl:attribute name="border-top">1px solid</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
|
||||
<!-- grey boxes around code (screen, programlisting) -->
|
||||
<xsl:param name="shade.verbatim" select="1"/>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
|
||||
<xsl:attribute name="border">thin #9F9F9F solid</xsl:attribute>
|
||||
<xsl:attribute name="margin">0pt</xsl:attribute>
|
||||
<xsl:attribute name="padding">0.5em</xsl:attribute>
|
||||
<!-- prevent page breaks in screen and programlisting tags -->
|
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- breaking long lines in code (screen, programlisting) -->
|
||||
<xsl:attribute-set name="monospace.verbatim.properties">
|
||||
<xsl:attribute name="wrap-option">wrap</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- don't show raw links in [ .. ] after a link -->
|
||||
<xsl:param name="ulink.show" select="0"/>
|
||||
|
||||
<!-- blue underlined hyperlink -->
|
||||
<xsl:attribute-set name="xref.properties">
|
||||
<xsl:attribute name="color">blue</xsl:attribute>
|
||||
<xsl:attribute name="text-decoration">underline</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- strong emphasis in bold -->
|
||||
<xsl:template match="emphasis[@role='strong']">
|
||||
<fo:inline font-family="Lato" font-weight="normal">
|
||||
<xsl:apply-templates/>
|
||||
</fo:inline>
|
||||
</xsl:template>
|
||||
|
||||
<!-- copyright in range instead of seperated years -->
|
||||
<xsl:param name="make.year.ranges" select="1" />
|
||||
|
||||
<!-- variablelist behavior (asciidoc's term:: lists) -->
|
||||
<!-- <xsl:param name="variablelist.term.break.after" select="1" /> -->
|
||||
|
||||
</xsl:stylesheet>
|
||||
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
|
||||
Loaded 100 of 3620 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user