Compare commits

..
19 Commits
Author SHA1 Message Date
Francis Lachapelle c4bc215a47 Merge to 2.0.7 2013-07-23 10:02:39 -04:00
Francis Lachapelle c9936d7ecf Merge to 2.0.7 2013-07-23 08:38:44 -04:00
Francis Lachapelle 885e59a2af Merge to 2.0.7 2013-07-19 13:46:37 -04:00
Jean Raby bf398889bf Merge to 2.0.6b 2013-06-27 11:36:30 -04:00
Ludovic Marcotte e26e3d7307 Revert "Properly escape the foldername to avoid XSS issues"
This reverts commit 045b275b27.
2013-06-27 11:15:41 -04:00
Ludovic Marcotte 045b275b27 Properly escape the foldername to avoid XSS issues 2013-06-27 11:06:07 -04:00
Jean Raby 7ec1973e0f Merge to 2.0.6a 2013-06-25 09:22:35 -04:00
Ludovic Marcotte a79a9c4eff Merge to 2.0.6
Conflicts:
	Documentation/SOGo Installation Guide.odt
2013-06-21 12:44:35 -04:00
Jean Raby f049e2430a Added ldap attribute mapping table 2013-04-22 12:25:22 -04:00
Jean Raby 59b3219f2d Merge to 2.05a 2013-04-16 15:20:19 -04:00
Francis Lachapelle e9eb8bdc86 Merge to 2.0.5 2013-04-11 12:56:34 -04:00
Francis Lachapelle 5e0c7ae4f2 Merge to 2.0.4b 2013-02-04 14:24:46 -05:00
Francis Lachapelle c1c0c1ab44 Merge to 2.0.4a 2013-01-30 08:54:00 -05:00
Francis Lachapelle a59fff785b Merge to 2.0.4 2013-01-25 14:01:10 -05:00
Francis Lachapelle 6a70db80e6 Merge to 2.0.3a 2012-12-07 09:35:03 -05:00
Francis Lachapelle d610630c8d Merge to 2.0.3 (again) 2012-12-06 13:08:47 -05:00
Francis Lachapelle 4dc7790015 Merge to 2.0.3 2012-12-06 10:40:33 -05:00
Francis Lachapelle 9dd000a2ca Merge to 2.0.2
Merge commit '1080bee3ba9749aad0dc28625081fc6a496f7280' into maint

Conflicts:
	OpenChange/MAPIStoreContext.h
	OpenChange/MAPIStoreContext.m
2012-11-15 10:10:48 -05:00
Wolfgang Sourdeau ce4084e528 getNewChangeNumbers: new wrapper for openchangedb_get_new_changeNumbers 2012-10-12 16:55:27 -04:00
3732 changed files with 164973 additions and 544857 deletions

No files matched your search

-163
View File
@@ -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"]
-67
View File
@@ -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
-72
View File
@@ -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))
-13
View File
@@ -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
View File
@@ -1 +0,0 @@
deb [signed-by=/etc/apt/keyrings/dovecot.gpg] http://repo.dovecot.org/ce-2.3.21.1/debian/bullseye bullseye main
-182
View File
@@ -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
-277
View File
@@ -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
-3
View File
@@ -1,3 +0,0 @@
FROM httpd:2.4
ADD httpd.conf /usr/local/apache2/conf/httpd.conf
-772
View File
@@ -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-----
-7
View File
@@ -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
-166
View File
@@ -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
-8
View File
@@ -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
-12
View File
@@ -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
View File
@@ -1 +0,0 @@
example.org
-52
View File
@@ -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
View File
@@ -1 +0,0 @@
@example.org root
-518
View File
@@ -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
}
-14
View File
@@ -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"
-147
View File
@@ -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
-53
View File
@@ -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
-107
View File
@@ -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. *
* *
* **************************************************************************/
WOPort = "0.0.0.0:50000";
/* Database configuration (mysql://, postgresql:// or oracle://) */
// 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;
}
-15
View File
@@ -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"
]
}
}
}
-108
View File
@@ -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:
-74
View File
@@ -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
```
-140
View File
@@ -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
```
+8 -58
View File
@@ -1,61 +1,11 @@
*._*
*.css
*.pyc
*.sax
*.swp
*.wox/
*/*/*.SOGo/
*/*/*/obj/
*/*/obj/
config.make
tags
*/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
-3
View File
@@ -1,3 +0,0 @@
[submodule "UI/WebServerResources/angular-material"]
path = UI/WebServerResources/angular-material
url = https://github.com/Alinto/material.git
+250 -48
View File
@@ -1,60 +1,262 @@
[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
[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-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
[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
-27
View File
@@ -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]
}
-28
View File
@@ -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
-16
View File
@@ -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
-35
View File
@@ -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
-52
View File
@@ -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 */
View File
Whitespace-only changes.
-54
View File
@@ -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
-399
View File
@@ -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&param2
*/
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
-11
View File
@@ -1,11 +0,0 @@
/*
Copyright (C) todo...
*/
#import <Foundation/NSObject.h>
@interface SOGoAPIProduct : NSObject
@end
@implementation SOGoAPIProduct
@end /* SOGoAPIProduct */
-33
View File
@@ -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
-110
View File
@@ -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 */
-33
View File
@@ -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
-42
View File
@@ -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 */
-34
View File
@@ -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)
-31
View File
@@ -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";
};
};
};
};
}
-40
View File
@@ -1,40 +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.
*/
#import <Foundation/NSObject.h>
@interface ActiveSyncProduct : NSObject
{
}
@end
@implementation ActiveSyncProduct
@end /* ActiveSyncProduct */
-42
View File
@@ -1,42 +0,0 @@
# GNUstep makefile
include common.make
BUNDLE_NAME = ActiveSync
ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct
ActiveSync_OBJC_FILES = \
ActiveSyncProduct.m \
iCalAlarm+ActiveSync.m \
iCalEvent+ActiveSync.m \
iCalRecurrenceRule+ActiveSync.m \
iCalTimeZone+ActiveSync.m \
iCalToDo+ActiveSync.m \
NSCalendarDate+ActiveSync.m \
NSData+ActiveSync.m \
NSDate+ActiveSync.m \
NGDOMElement+ActiveSync.m \
NGMimeMessage+ActiveSync.m \
NGVCard+ActiveSync.m \
NSArray+SyncCache.m \
NSString+ActiveSync.m \
SOGoActiveSyncDispatcher.m \
SOGoActiveSyncDispatcher+Sync.m \
SOGoMailObject+ActiveSync.m \
SOGoSyncCacheObject.m \
SoObjectWebDAVDispatcher+ActiveSync.m
ActiveSync_RESOURCE_FILES += \
product.plist
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_LDFLAGS += -Wl,--no-as-needed -lwbxml2
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/bundle.make
-include GNUmakefile.postamble
-4
View File
@@ -1,4 +0,0 @@
ifeq ($(HAS_LIBRARY_ssl),yes)
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
BUNDLE_LIBS += -lcrypto
endif
-25
View File
@@ -1,25 +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.
-43
View File
@@ -1,43 +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.
*/
#ifndef __NGDOMELEMENTACTIVESYNC_H__
#define __NGDOMELEMENTACTIVESYNC_H__
#import <DOM/DOMElement.h>
@class NSDictionary;
@interface NGDOMElement (ActiveSync)
- (NSDictionary *) applicationData;
@end
#endif // NGDOMELEMENTACTIVESYNC
-228
View File
@@ -1,228 +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 "NGDOMElement+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
static NSArray *asElementArray = nil;
static NSArray *considerAsSameArray = nil;
@implementation NGDOMElement (ActiveSync)
- (BOOL) isTextNode
{
id <DOMNodeList> children;
id <DOMElement> element;
int i;
if ([self nodeType] == DOM_TEXT_NODE)
return YES;
children = [self childNodes];
for (i = 0; i < [children length]; i++)
{
element = [children objectAtIndex: i];
if ([element nodeType] != DOM_TEXT_NODE)
return NO;
}
return YES;
}
//
// We must handle "inner data" like this:
//
// <ApplicationData>
// <Flag xmlns="Email:">
// <FlagStatus>2</FlagStatus>
// <FlagType>Flag for follow up</FlagType>
// </Flag>
// </ApplicationData>
//
// and stuff like that:
//
// <Attendees xmlns="Calendar:">
// <Attendee>
// <Attendee_Email>sogo1@example.com</Attendee_Email>
// <Attendee_Name>John Doe</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// <Attendee>
// <Attendee_Email>sogo2@example.com</Attendee_Email>
// <Attendee_Name>Balthazar César</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// <Attendee>
// <Attendee_Email>sogo3@example.com</Attendee_Email>
// <Attendee_Name>Wolfgang Fritz</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// </Attendees>
//
- (NSDictionary *) applicationData
{
NSMutableDictionary *data;
id <DOMNodeList> children;
id <DOMElement> element;
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];
data = [NSMutableDictionary dictionary];
children = [self childNodes];
for (i = 0; i < [children length]; i++)
{
element = [children objectAtIndex: i];
if ([element nodeType] == DOM_ELEMENT_NODE)
{
NSString *tag;
id value;
tag = [element tagName];
count = [(NSArray *)[element childNodes] count];
// We check if the node is a text one or if all its
// children are text nodes. This is important to avoid side-effects
// in SOPE where "foo & bar" would result into 3 childnodes instead
// of just one.
if ([(id)element isTextNode])
{
value = [(id)element textValue];
}
// Handle inner data - see above for samples
else
{
NSMutableArray *innerElements;
id <DOMElement> innerElement;
NSArray *childNodes;
NSString *innerTag;
BOOL same;
int j;
childNodes = (NSArray *)[element childNodes];
innerElements = [NSMutableArray array];
innerTag = nil;
same = YES;
for (j = 1; j < count; j++)
{
innerElement = [childNodes objectAtIndex: j];
if ([innerElement nodeType] == DOM_ELEMENT_NODE)
{
if (!innerTag)
innerTag = [innerElement tagName];
if ([innerTag isEqualToString: [innerElement tagName]] || [considerAsSameArray containsObject: innerTag])
{
if ([(id)innerElement isTextNode])
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
else
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
}
else
{
same = NO;
break;
}
}
}
if (same && [asElementArray containsObject: innerTag])
value = innerElements;
else
{
value = [(NGDOMElement *)element applicationData];
// Don't set empty values like Foo = {}
if (![value count])
value = nil;
}
}
if (value && tag)
[data setObject: value forKey: tag];
} // if ([element nodeType] == DOM_ELEMENT_NODE)
}
return data;
}
@end
-43
View File
@@ -1,43 +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.
*/
#ifndef __NGMIMEMESSAGEACTIVESYNC_H__
#define __NGMIMEMESSAGEACTIVESYNC_H__
#import <NGMail/NGMimeMessage.h>
@class NSArray;
@interface NGMimeMessage (ActiveSync)
- (NSArray *) allBareRecipients;
@end
#endif
-84
View File
@@ -1,84 +0,0 @@
/*
Copyright (c) 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 "NGMimeMessage+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <NGMail/NGMailAddress.h>
#import <NGMail/NGMailAddressParser.h>
#import <SOGo/NSString+Utilities.h>
@implementation NGMimeMessage (ActiveSync)
- (NSArray *) allRecipients
{
NGMailAddressParser *parser;
NSEnumerator *addressList;
NSMutableArray *allRecipients;
NGMailAddress *address;
NSEnumerator *recipients;
NSString *s;
NSString *fieldNames[] = {@"to", @"cc", @"bcc"};
unsigned int count;
allRecipients = [NSMutableArray arrayWithCapacity: 16];
for (count = 0; count < 3; count++)
{
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]];
}
}
return allRecipients;
}
- (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
-47
View File
@@ -1,47 +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.
*/
#ifndef __NGVCARDACTIVESYNC_H__
#define __NGVCARDACTIVESYNC_H__
#import <NGCards/NGVCard.h>
@class NSDictionary;
@class NSString;
@class WOContext;
@interface NGVCard (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
-619
View File
@@ -1,619 +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.
*/
#import "NGVCard+ActiveSync.h"
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <Contacts/NGVCard+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#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;
NSString *url;
id o;
int i;
s = [NSMutableString string];
n = [self n];
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]];
if ((o = [[self org] flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<Department xmlns=\"Contacts:\">%@</Department>", [o activeSyncRepresentationInContext: context]];
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Contacts:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Contacts:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
elements = [self childrenWithTag: @"url"
andAttribute: @"type"
havingValue: @"work"];
if ([elements count] > 0)
{
url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
[s appendFormat: @"<WebPage xmlns=\"Contacts:\">%@</WebPage>", [url activeSyncRepresentationInContext: context]];
}
if ((o = [[self uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]))
[s appendFormat: @"<IMAddress xmlns=\"Contacts:\">%@</IMAddress>", [o activeSyncRepresentationInContext: context]];
if ((o = [self nickname]))
[s appendFormat: @"<NickName xmlns=\"Contacts:\">%@</NickName>", [o activeSyncRepresentationInContext: context]];
if ((o = [self title]))
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
if ((o = [self preferredEMail]))
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", [o activeSyncRepresentationInContext: context]];
// Secondary email addresses (2 and 3)
emails = [self secondaryEmails];
for (i = 0; i < [emails count]; i++)
{
o = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, [o activeSyncRepresentationInContext: context], i+2];
if (i == 1)
break;
}
// Telephone numbers
if ((o = [self workPhone]) && [o length])
[s appendFormat: @"<BusinessPhoneNumber xmlns=\"Contacts:\">%@</BusinessPhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self homePhone]) && [o length])
[s appendFormat: @"<HomePhoneNumber xmlns=\"Contacts:\">%@</HomePhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self fax]) && [o length])
[s appendFormat: @"<BusinessFaxNumber xmlns=\"Contacts:\">%@</BusinessFaxNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self mobile]) && [o length])
[s appendFormat: @"<MobilePhoneNumber xmlns=\"Contacts:\">%@</MobilePhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self pager]) && [o length])
[s appendFormat: @"<PagerNumber xmlns=\"Contacts:\">%@</PagerNumber>", [o activeSyncRepresentationInContext: context]];
// Home Address
addresses = [self childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"home"];
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>", 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]];
if ((o = [homeAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<HomeCountry xmlns=\"Contacts:\">%@</HomeCountry>", [o activeSyncRepresentationInContext: context]];
}
// Work Address
addresses = [self childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"work"];
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];
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<BusinessState xmlns=\"Contacts:\">%@</BusinessState>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<BusinessPostalCode xmlns=\"Contacts:\">%@</BusinessPostalCode>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 6 forKey: @""]))
[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]];
}
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: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
if ((o = [self photo]))
[s appendFormat: @"<Picture xmlns=\"Contacts:\">%@</Picture>", o];
return s;
}
//
//
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
CardElement *element;
NSMutableArray *addressLines, *other_addresses;
id o, l, m, f, p, s;
l = m = f = p = s = nil;
// Contact's note
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setNote: o];
// 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]];
}
else if (![self _isGhosted: @"Birthday" inContext: context])
{
[self setBday: @""];
}
//
// Business address information
//
// BusinessStreet
// BusinessCity
// BusinessPostalCode
// BusinessState
// 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: @""];
}
//
// Home address information
//
// HomeStreet
// HomeCity
// HomePostalCode
// HomeState
// 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: @""];
}
// 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])
{
element = [self elementWithTag: @"email" ofType: @"work"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
if ((o = [theValues objectForKey: @"Email2Address"]) || ![self _isGhosted: @"Email2Address" inContext: context])
{
element = [self elementWithTag: @"email" ofType: @"home"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
// 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])
{
element = [self elementWithTag: @"email" ofType: @"three"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
// Formatted name
// 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];
// IM information
if ((o = [theValues objectForKey: @"IMAddress"]) || ![self _isGhosted: @"IMAddress" inContext: context])
[[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: @""];
}
if ((o = [theValues objectForKey: @"HomePhoneNumber"]) || ![self _isGhosted: @"HomePhoneNumber" inContext: context])
{
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: @""];
}
if ((o = [theValues objectForKey: @"BusinessFaxNumber"]) || ![self _isGhosted: @"BusinessFaxNumber" inContext: context])
{
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: @""];
}
// Job's title
if ((o = [theValues objectForKey: @"JobTitle"]) || ![self _isGhosted: @"JobTitle" inContext: context])
[self setTitle: o];
// WebPage (work)
if ((o = [theValues objectForKey: @"WebPage"]) || ![self _isGhosted: @"WebPage" inContext: context])
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: o forKey: @""];
if ((o = [theValues objectForKey: @"NickName"]) || ![self _isGhosted: @"NickName" inContext: context])
[self setNickname: o];
if ((o = [theValues objectForKey: @"Picture"]))
[self setPhoto: o];
}
@end
-49
View File
@@ -1,49 +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.
*/
#ifndef __NSARRAYSYNCCACHE_H__
#define __NSARRAYSYNCCACHE_H__
#import <Foundation/NSArray.h>
@class NSDictionary;
@interface NSMutableArray (SyncCache)
- (id) initWithDictionary: (NSDictionary *) theDictionary;
@end
@interface NSArray (SyncCache)
- (NSDictionary *) dictionaryValue;
@end
#endif
-84
View File
@@ -1,84 +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.
*/
#import "NSArray+SyncCache.h"
#import <Foundation/NSDictionary.h>
#include "SOGoSyncCacheObject.h"
@implementation NSMutableArray (SyncCache)
- (id) initWithDictionary: (NSDictionary *) theDictionary
{
SOGoSyncCacheObject *o;
NSArray *allKeys;
id key;
int i;
self = [self initWithCapacity: [theDictionary count]];
allKeys = [theDictionary allKeys];
for (i = 0; i < [allKeys count]; i++)
{
key = [allKeys objectAtIndex: i];
o = [SOGoSyncCacheObject syncCacheObjectWithUID: key
sequence: [theDictionary objectForKey: key]];
[self addObject: o];
}
return self;
}
@end
//
//
//
@implementation NSArray (SyncCache)
- (NSDictionary *) dictionaryValue
{
NSMutableDictionary *d;
SOGoSyncCacheObject *o;
int i;
d = [NSMutableDictionary dictionary];
for (i = 0; i < [self count]; i++)
{
o = [self objectAtIndex: i];
[d setObject: [o sequence] forKey: [o uid]];
}
return d;
}
@end
-43
View File
@@ -1,43 +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.
*/
#ifndef __NSCALENDARDATEACTIVESYNC_H__
#define __NSCALENDARDATEACTIVESYNC_H__
#import <Foundation/NSCalendarDate.h>
@class NSString;
@interface NSCalendarDate (ActiveSync)
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType;
@end
#endif
-86
View File
@@ -1,86 +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.
*/
#import "NSCalendarDate+ActiveSync.h"
#import <Foundation/NSString.h>
#define ONE_DAY 86400
@implementation NSCalendarDate (ActiveSync)
//
// See http://msdn.microsoft.com/en-us/library/gg709713(v=exchg.80).aspx for available types
//
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType
{
NSCalendarDate *d;
d = [NSCalendarDate calendarDate];
if (d)
{
int value;
switch ([theFilterType intValue])
{
case 1:
value = ONE_DAY;
break;
case 2:
value = 3 * ONE_DAY;
break;
case 3:
value = 7 * ONE_DAY;
break;
case 4:
value = 14 * ONE_DAY;
break;
case 5:
value = 30 * ONE_DAY;
break;
case 6:
value = 90 * ONE_DAY;
break;
case 7:
value = 180 * ONE_DAY;
break;
case 0:
case 8:
default:
return nil;
}
return [d initWithTimeIntervalSinceNow: -value];
}
return d;
}
@end
-46
View File
@@ -1,46 +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.
*/
#ifndef __NSDATAACTIVESYNC_H__
#define __NSDATAACTIVESYNC_H__
#import <Foundation/NSData.h>
@class NSString;
@class WOContext;
@interface NSData (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (NSData *) wbxml2xml;
- (NSData *) xml2wbxml;
@end
#endif
-182
View File
@@ -1,182 +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.
*/
#import "NSData+ActiveSync.h"
#import <Foundation/NSProcessInfo.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#define WBXMLDEBUG 0
@implementation NSData (ActiveSync)
- (void) _dumpToFile
{
BOOL debugOn;
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];
}
}
//
// Encodes the data in base64 and strip newline characters
//
- (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);
}
- (NSData *) wbxml2xml
{
WBXMLGenXMLParams params;
NSData *data;
unsigned int wbxml_len, xml_len, ret;
unsigned char *wbxml, *xml;
wbxml = (unsigned char*)[self bytes];
wbxml_len = [self length];
xml = NULL;
xml_len = 0;
params.lang = WBXML_LANG_ACTIVESYNC;
params.gen_type = WBXML_GEN_XML_INDENT;
params.indent = 1;
params.keep_ignorable_ws = FALSE;
ret = wbxml_conv_wbxml2xml_withlen(wbxml, wbxml_len, &xml, &xml_len, &params);
if (ret != WBXML_OK)
{
[self errorWithFormat: @"wbxml2xml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
data = [NSData dataWithBytesNoCopy: xml length: xml_len freeWhenDone: YES];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.decoded" atomically: YES];
#endif
return data;
}
- (NSData *) xml2wbxml
{
WBXMLConvXML2WBXML *conv;
NSData *data;
unsigned int wbxml_len, xml_len, ret;
unsigned char *wbxml, *xml;
xml = (unsigned char*)[self bytes];
xml_len = [self length];
wbxml = NULL;
wbxml_len = 0;
conv = NULL;
ret = wbxml_conv_xml2wbxml_create(&conv);
if (ret != WBXML_OK)
{
[self logWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
wbxml_conv_xml2wbxml_enable_preserve_whitespaces(conv);
// From libwbxml's changelog in v0.11.0: "The public ID is set to unknown and the DTD is not included. This is required for Microsoft ActiveSync."
wbxml_conv_xml2wbxml_disable_public_id(conv);
wbxml_conv_xml2wbxml_disable_string_table(conv);
ret = wbxml_conv_xml2wbxml_run(conv, xml, xml_len, &wbxml, &wbxml_len);
if (ret != WBXML_OK)
{
[self errorWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
return nil;
}
data = [NSData dataWithBytesNoCopy: wbxml length: wbxml_len freeWhenDone: YES];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.encoded" atomically: YES];
#endif
wbxml_conv_xml2wbxml_destroy(conv);
return data;
}
@end
-45
View File
@@ -1,45 +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.
*/
#ifndef __NSDATEACTIVESYNC_H__
#define __NSDATEACTIVESYNC_H__
#import <Foundation/NSDate.h>
@class NSString;
@class WOContext;
@interface NSDate (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context;
@end
#endif
-52
View File
@@ -1,52 +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.
*/
#import "NSDate+ActiveSync.h"
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
@implementation NSDate (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self descriptionWithCalendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
}
//
// From [MS-ASDTYPE].pdf - section 2.3 "Dates and times in calendar items MUST NOT include punctuation separators."
//
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context
{
return [self descriptionWithCalendarFormat: @"%Y%m%dT%H%M%SZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
}
@end
-59
View File
@@ -1,59 +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.
*/
#ifndef __NSSTRINGACTIVESYNC_H__
#define __NSSTRINGACTIVESYNC_H__
#import <Foundation/NSString.h>
#include "SOGoActiveSyncConstants.h"
@class NSCalendarDate;
@class NSData;
@class WOContext;
@interface NSString (ActiveSync)
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (int) activeSyncFolderType;
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
- (NSCalendarDate *) calendarDate;
- (NSString *) deviceId;
- (NSString *) deviceType;
- (NSString *) attachmentName;
- (NSString *) command;
- (NSString *) collectionid;
- (NSString *) itemid;
- (BOOL) acceptsMultiPart;
- (NSData *) convertHexStringToBytes;
- (NSString *) protocolVersion;
@end
#endif
-457
View File
@@ -1,457 +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 "NSString+ActiveSync.h"
#include <Foundation/NSArray.h>
#include <Foundation/NSCalendarDate.h>
#include <SOGo/NSString+Utilities.h>
#include <SOGo/NSData+Crypto.h>
#include <NGExtensions/NGBase64Coding.h>
#include <NGExtensions/NSString+misc.h>
static NSArray *easCommandCodes = nil;
static NSArray *easCommandParameters = nil;
@implementation NSString (ActiveSync)
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
{
if (folderType == ActiveSyncEventFolder)
{
int len;
len = [self length];
if (len > 4 && [self hasSuffix: @".ics"])
return [self substringToIndex: len-4];
else
return [NSString stringWithFormat: @"%@.ics", self];
}
return self;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self safeStringByEscapingXMLString: YES];
}
- (int) activeSyncFolderType
{
if ([self isEqualToString: @"inbox"])
return 2;
else if ([self isEqualToString: @"draft"])
return 3;
else if ([self isEqualToString: @"sent"])
return 5;
else if ([self isEqualToString: @"trash"])
return 4;
return 12;
}
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
{
NSString *realCollectionId, *v;
*folderType = ActiveSyncGenericFolder;
v = [self stringByUnescapingURL];
if ([v hasPrefix: @"vevent/"])
{
realCollectionId = [v substringFromIndex: 7];
*folderType = ActiveSyncEventFolder;
}
else if ([v hasPrefix: @"vtodo/"])
{
realCollectionId = [v substringFromIndex: 6];
*folderType = ActiveSyncTaskFolder;
}
else if ([v hasPrefix: @"vcard/"])
{
realCollectionId = [v substringFromIndex: 6];
*folderType = ActiveSyncContactFolder;
}
else if ([v hasPrefix: @"mail/"])
{
realCollectionId = [[v stringByUnescapingURL] substringFromIndex: 5];
*folderType = ActiveSyncMailFolder;
}
else
{
realCollectionId = nil;
}
return realCollectionId;
}
//
// 2014-01-16T05:00:00.000Z
//
// See http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSCalendarDate.html#method$NSCalendarDate-initWithString$calendarFormat$ for the format details.
//
- (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"];
if (!o)
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
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;
NSString *s;
int i;
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)
{
NSString *deviceType, *parameterValue;
NSData *queryString;
int cmd_code, deviceid_length, policy_length, devicetype_length, parameter_code, parameter_length, i;
const char* qs_bytes;
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
if (![queryString length])
return nil;
qs_bytes = (const char*)[queryString bytes];
if (!easCommandCodes)
{
easCommandCodes = [NSArray arrayWithObjects:@"Sync", @"SendMail", @"SmartForward", @"SmartReply", @"GetAttachment", @"na", @"na", @"na", @"na",
@"FolderSync", @"FolderCreate", @"FolderDelete", @"FolderUpdate", @"MoveItems", @"GetItemEstimate", @"MeetingResponse",
@"Search", @"Settings", @"Ping", @"ItemOperations", @"Provision", @"ResolveRecipients", @"ValidateCert", nil];
RETAIN(easCommandCodes);
}
if (!easCommandParameters)
{
easCommandParameters = [NSArray arrayWithObjects:@"AttachmentName", @"CollectionId", @"na", @"ItemId", @"LongId", @"na", @"Occurrence", @"Options", @"User", nil];
RETAIN(easCommandParameters);
}
// 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)
deviceid_length = qs_bytes[4];
[components addObject: [NSString stringWithFormat: @"deviceId=%@", [[NSData encodeDataAsHexString: [queryString subdataWithRange: NSMakeRange(5, deviceid_length)]] uppercaseString]]];
// Device type length and type (variable)
policy_length = qs_bytes[5+deviceid_length];
devicetype_length = qs_bytes[5+deviceid_length+1+policy_length];
deviceType = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(5+deviceid_length+1+policy_length+1, devicetype_length)]
encoding: NSASCIIStringEncoding];
AUTORELEASE(deviceType);
[components addObject: [NSString stringWithFormat: @"deviceType=%@", deviceType]];
// Command Parameters
i = 5+deviceid_length+1+policy_length+1+devicetype_length;
while (i < [queryString length])
{
parameter_code = qs_bytes[i];
parameter_length = qs_bytes[i+1];
parameterValue = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(i+1+1, parameter_length)]
encoding: NSASCIIStringEncoding];
AUTORELEASE(parameterValue);
// parameter_code 7 == Options
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
if (parameter_code == 7 && ! [parameterValue isEqualToString: @"\000"] )
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
else
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code], parameterValue]];
i = i + 1 + 1 + parameter_length;
}
}
for (i = 0; i < [components count]; i++)
{
s = [components objectAtIndex: i];
if ([[s uppercaseString] hasPrefix: theParameter])
return [s substringFromIndex: [theParameter length]];
}
return nil;
}
//
// This method extracts the "DeviceId" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
//
- (NSString *) deviceId
{
NSString *s;
s = [self _valueForParameter: @"DEVICEID="];
if (!s)
s = @"Unknown";
return s;
}
//
// This method extracts the "DeviceType" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
//
- (NSString *) deviceType
{
NSString *s;
s = [self _valueForParameter: @"DEVICETYPE="];
if (!s)
s = @"Unknown";
return s;
}
// This method extracts the "AttachmentName" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=GetAttachment&User=sogo&DeviceId=HTCa04b4932597acd3f2dc1a918b9728&DeviceType=htcvision&AttachmentName=mail/TestFldr/8/2
//
- (NSString *) attachmentName
{
NSString *s;
s = [self _valueForParameter: @"ATTACHMENTNAME="];
if (!s)
s = @"Unknown";
return s;
}
//
//
//
- (NSString *) command
{
NSString *s;
s = [self _valueForParameter: @"CMD="];
if (!s)
s = @"Unknown";
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.
//
- (char) _decodeHexByte: (char) byteChar
{
char newByte;
if (byteChar >= 48 && byteChar <= 57)
newByte = (uint8_t) byteChar - 48;
else if (byteChar >= 65 && byteChar <= 70)
newByte = (uint8_t) byteChar - 55;
else if (byteChar >= 97 && byteChar <= 102)
newByte = (uint8_t) byteChar - 87;
else
newByte = -1;
return newByte;
}
//
// FIXME: combine with our OpenChange code.
//
- (BOOL) _decodeHexByte: (uint8_t *) byte
atPos: (NSUInteger) pos
{
BOOL error = NO;
char newByte;
unichar byteChar;
byteChar = [self characterAtIndex: pos];
if (byteChar < 256)
{
newByte = [self _decodeHexByte: (char) byteChar];
if (newByte == -1)
error = YES;
else
*byte = newByte;
}
else
error = YES;
return error;
}
//
// FIXME: combine with our OpenChange code.
//
- (BOOL) _decodeHexPair: (uint8_t *) byte
atPos: (NSUInteger) pos
{
BOOL error;
uint8_t lowValue, highValue;
error = [self _decodeHexByte: &highValue atPos: pos];
if (!error)
{
error = [self _decodeHexByte: &lowValue atPos: pos + 1];
if (!error)
*byte = highValue << 4 | lowValue;
}
return error;
}
//
// FIXME: combine with our OpenChange code.
//
- (NSData *) convertHexStringToBytes
{
NSUInteger count, strLen, bytesLen;
uint8_t *bytes, *currentByte;
NSData *decoded = nil;
BOOL error = NO;
strLen = [self length];
if ((strLen % 2) == 0)
{
bytesLen = strLen / 2;
bytes = NSZoneCalloc (NULL, bytesLen, sizeof (uint8_t));
currentByte = bytes;
for (count = 0; !error && count < strLen; count += 2)
{
error = [self _decodeHexPair: currentByte atPos: count];
currentByte++;
}
if (error)
NSZoneFree (NULL, bytes);
else
decoded = [NSData dataWithBytesNoCopy: bytes
length: bytesLen
freeWhenDone: YES];
}
return decoded;
}
@end
-12
View File
@@ -1,12 +0,0 @@
In order to use this software in production environments, you need to
get a proper usage license from Microsoft. Please contact them directly
to negotiate the fees associated to your user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/
and send an email to iplicreq@microsoft.com
Inverse inc. provides this software for free, but is not responsible
for anything related to its usage.
-42
View File
@@ -1,42 +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.
*/
#ifndef __SOGOACTIVESYNCCONSTANTS_H__
#define __SOGOACTIVESYNCCONSTANTS_H__
typedef enum
{
ActiveSyncGenericFolder = 0,
ActiveSyncMailFolder = 1,
ActiveSyncContactFolder = 2,
ActiveSyncEventFolder = 3,
ActiveSyncTaskFolder = 4,
} SOGoMicrosoftActiveSyncFolderType;
#endif
@@ -1,46 +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.
*/
#ifndef __SOGOACTIVESYNCDISPATCHERSYNC_H__
#define __SOGOACTIVESYNCDISPATCHERSYNC_H__
#import "SOGoActiveSyncDispatcher.h"
#import <DOM/DOMElement.h>
@class WOResponse;
@interface SOGoActiveSyncDispatcher (Sync)
- (void) processSync: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse;
@end
#endif // SOGOACTIVESYNCDISPATCHERSYNC
File diff suppressed because it is too large. Load diff
-69
View File
@@ -1,69 +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>
#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;
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
- (NSException *) dispatchRequest: (id) theRequest
inResponse: (id) theResponse
context: (id) theContext;
- (NSURL *) folderTableURL;
- (void) ensureFolderTableExists;
- (BOOL) easShouldTerminate;
@end
File diff suppressed because it is too large. Load diff
-51
View File
@@ -1,51 +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.
*/
#ifndef __SOGOMAILOBJECTACTIVESYNC_H__
#define __SOGOMAILOBJECTACTIVESYNC_H__
#import <Mailer/SOGoMailObject.h>
@class iCalCalendar;
@class NSDictionary;
@class WOContext;
@interface SOGoMailObject (ActiveSync)
- (iCalCalendar *) calendarFromIMIPMessage;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (NSString *) storeMail: (NSDictionary *) theValues
inBuffer: (NSMutableString *) theBuffer
inContext: (WOContext *) _context;
@end
#endif
File diff suppressed because it is too large. Load diff
-56
View File
@@ -1,56 +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.
*/
#ifndef __SOGOSYNCCACHEOBJECT_H__
#define __SOGOSYNCCACHEOBJECT_H__
#import <Foundation/NSObject.h>
@class NSNull;
@interface SOGoSyncCacheObject : NSObject
{
@public
id _uid;
id _sequence;
}
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
- (id) uid;
- (void) setUID: (id) theUID;
- (id) sequence;
- (void) setSequence: (id) theSequence;
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject;
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject;
@end
#endif
-131
View File
@@ -1,131 +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 "SOGoSyncCacheObject.h"
#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]))
{
_uid = nil;
_sequence = nil;
}
return self;
}
+ (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]])];
return [o autorelease];
}
- (void) dealloc
{
RELEASE(_uid);
RELEASE(_sequence);
[super dealloc];
}
- (id) uid
{
return [_uid description];
}
- (void) setUID: (id) theUID
{
ASSIGN(_uid, theUID);
}
- (id) sequence
{
return ([_sequence isKindOfClass: NSNullK] ? _sequence : [_sequence description]);
}
- (void) setSequence: (id) theSequence
{
ASSIGN(_sequence, theSequence);
}
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
{
return [self->_uid compare: theSyncCacheObject->_uid];
}
//
// We might get NSNull values here, so if both are NSNull instances,
// we sort by UID. If both sequences are equal, we also sort by UID.
//
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
{
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]])
return NSOrderedDescending;
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)
return [self compareUID: theSyncCacheObject];
return [self->_sequence compare: theSyncCacheObject->_sequence];
}
- (NSString *) description
{
return [NSString stringWithFormat: @"%@-%@", _uid, _sequence];
}
@end
@@ -1,104 +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.
*/
#import <NGObjWeb/SoObjectWebDAVDispatcher.h>
#include <NGObjWeb/SoObject+SoDAV.h>
#include <NGObjWeb/WEClientCapabilities.h>
#include <NGObjWeb/WOContext.h>
#include <NGObjWeb/WORequest.h>
#include <NGObjWeb/WOResponse.h>
#import <Foundation/NSArray.h>
@interface SoObjectWebDAVDispatcher (ActiveSync)
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
- (id) doOPTIONS:(WOContext *)_ctx;
@end
@implementation SoObjectWebDAVDispatcher (ActiveSync)
- (id) doOPTIONS:(WOContext *)_ctx
{
WOResponse *response;
/*
See example: http://msdn.microsoft.com/en-us/library/ee204257(v=exchg.80).aspx
*/
if ([[[_ctx request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
{
response = [_ctx response];
[response setStatus: 200];
[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: @"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"];
}
else
{
NSArray *tmp;
id result;
/* this checks whether the object provides a specific OPTIONS method */
if ((result = [self _callObjectMethod:@"OPTIONS" inContext:_ctx]) != nil)
return result;
response = [_ctx response];
[response setStatus:200 /* OK */];
if ((tmp = [self->object davAllowedMethodsInContext:_ctx]) != nil)
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"allow"];
if ([[[_ctx request] clientCapabilities] isWebFolder]) {
/*
As described over here:
http://teyc.editthispage.com/2005/06/02
This page also says that: "MS-Auth-Via header is not required to work
with Web Folders".
*/
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"public"];
}
if ((tmp = [self->object davComplianceClassesInContext:_ctx]) != nil)
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"dav"];
}
return response;
}
@end
-34
View File
@@ -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)
-46
View File
@@ -1,46 +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.
*/
#ifndef __ICALALARMACTIVESYNC_H__
#define __ICALALARMACTIVESYNC_H__
#import <NGCards/iCalAlarm.h>
@class NSString;
@class WOContext;
@interface iCalAlarm (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
-128
View File
@@ -1,128 +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.
*/
#import "iCalAlarm+ActiveSync.h"
#import <Foundation/NSDictionary.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSString+misc.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]])
{
// 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]];
}
return s;
}
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
iCalTrigger *trigger;
id o;
if ((o = [theValues objectForKey: @"Reminder"]))
{
// 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: @""];
else
{
if (([o intValue] % 1440) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] 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: @""];
}
}
}
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
-49
View File
@@ -1,49 +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.
*/
#ifndef __ICALEVENTACTIVESYNC_H__
#define __ICALEVENTACTIVESYNC_H__
#import <NGCards/iCalEvent.h>
@class NSString;
@class WOContext;
@interface iCalEvent (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (void) changeParticipationStatus: (NSDictionary *) theValues
inContext: (WOContext *) context
component: (id) component;
@end
#endif
-959
View File
@@ -1,959 +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.
*/
#import "iCalEvent+ActiveSync.h"
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.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"
#include "iCalTimeZone+ActiveSync.h"
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation iCalEvent (ActiveSync)
- (int) _attendeeStatus: (iCalPerson *) attendee
{
int attendee_status;
attendee_status = 5;
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
attendee_status = 3;
else if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
attendee_status = 4;
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
attendee_status = 2;
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;
iCalPerson *organizer, *attendee;
iCalTimeZone *tz;
id o;
int v, i, meetingStatus;
NSTimeZone *userTimeZone;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
s = [NSMutableString string];
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
// DTStamp -- http://msdn.microsoft.com/en-us/library/ee219470(v=exchg.80).aspx
if ([self timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
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)
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
else
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
// 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)
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
else
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
if (!tz)
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
if (![self recurrenceId])
[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])
{
[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]];
}
}
// Attendees
attendees = [self attendees];
if ([attendees count])
{
int i, attendee_status, attendee_type;
[s appendString: @"<Attendees xmlns=\"Calendar:\">"];
for (i = 0; i < [attendees count]; i++)
{
[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]];
attendee_status = [self _attendeeStatus: attendee];
[s appendFormat: @"<Attendee_Status xmlns=\"Calendar:\">%d</Attendee_Status>", attendee_status];
// FIXME: handle resource
if ([[attendee role] caseInsensitiveCompare: @"REQ-PARTICIPANT"] == NSOrderedSame)
attendee_type = 1;
else
attendee_type = 2;
[s appendFormat: @"<Attendee_Type xmlns=\"Calendar:\">%d</Attendee_Type>", attendee_type];
[s appendString: @"</Attendee>"];
}
[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
if ([self userIsAttendee: [context activeUser]])
{
iCalPerson *attendee;
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: @"<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]];
}
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])
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
// 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]];
}
// Importance - NOT SUPPORTED - DO NOT ENABLE
//o = [self priority];
//if ([o isEqualToString: @"9"])
// v = 0;
//else if ([o isEqualToString: @"1"])
// v = 2;
//else
// v = 1;
//[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>"];
}
}
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else 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];
[s appendString: [alarm activeSyncRepresentationInContext: context]];
}
// Exceptions
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>"];
}
}
if (![self recurrenceId])
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
return s;
}
//
// To understand meeting requests/responses, see:
//
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/22/working-with-meeting-requests-in-exchange-activesync.aspx
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/29/working-with-meeting-responses-in-exchange-activesync.aspx
//
//
// Here is an example of a Sync call when sogo10 accepts an invitation from sogo3:
//
// <Change>
// <ServerId>2978-52EA9D00-1-A253E70.ics</ServerId>
// <ApplicationData>
// <TimeZone xmlns="Calendar:">LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</TimeZone>
// <AllDayEvent xmlns="Calendar:">0</AllDayEvent>
// <StartTime xmlns="Calendar:">20140207T130000Z</StartTime>
// <EndTime xmlns="Calendar:">20140207T140000Z</EndTime>
// <DTStamp xmlns="Calendar:">20140130T185245Z</DTStamp>
// <Subject xmlns="Calendar:">test 8</Subject>
// <Sensitivity xmlns="Calendar:">0</Sensitivity>
// <Body xmlns="AirSyncBase:">
// <Type>1</Type>
// <Data/>
// </Body>
// <Organizer_Email xmlns="Calendar:">sogo3@example.com</Organizer_Email>
// <UID xmlns="Calendar:">2978-52EA9D00-1-A253E70</UID>
// <Attendees xmlns="Calendar:">
// <Attendee>
// <Attendee_Name>sogo10</Attendee_Name>
// <Attendee_Email>sogo10@example.com</Attendee_Email>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// </Attendees>
// <BusyStatus xmlns="Calendar:">2</BusyStatus>
// <MeetingStatus xmlns="Calendar:">3</MeetingStatus>
// <Organizer_Name xmlns="Calendar:">Wolfgang Fritz</Organizer_Name>
// </ApplicationData>
// </Change>
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
iCalDateTime *start, *end; //, *oldstart;
NSCalendarDate *oldstart;
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
iCalAlarm *alarm;
id o;
int deltasecs;
BOOL isAllDay;
NSMutableArray *occurences;
occurences = [NSMutableArray arrayWithArray: [[self parent] events]];
if ((o = [theValues objectForKey: ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0) ? @"ClientUid" : @"UID"]))
[self setUid: o];
// FIXME: merge with iCalToDo
if ((o = [theValues objectForKey: @"Subject"]))
[self setSummary: o];
isAllDay = NO;
if ([[theValues objectForKey: @"AllDayEvent"] intValue])
{
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"];
}
//
// 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];
// 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];
}
// 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"]))
[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)
{
[start setDate: o];
[start setTimeZone: nil];
}
else
{
[start setDateTime: o];
}
// Calculate delta if start date has been changed.
if (oldstart)
deltasecs = [[start dateTime ] timeIntervalSinceDate: oldstart] * -1;
}
if ((o = [theValues objectForKey: @"EndTime"]))
{
o = [o calendarDate];
end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"];
[end setTimeZone: tz];
if (isAllDay)
{
[end setDate: o];
[end setTimeZone: nil];
}
else
{
[end setDateTime: o];
}
}
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
{
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
//
[alarm takeActiveSyncValues: theValues inContext: context];
[self removeAllAlarms];
[self addToAlarms: alarm];
RELEASE(alarm);
}
else
{
// We remove existing alarm since no reminder in the ActiveSync payload
[self removeAllAlarms];
}
// Recurrence
if ((o = [theValues objectForKey: @"Recurrence"]) && [o isKindOfClass: [NSDictionary class]])
{
iCalRecurrenceRule *rule;
rule = [[iCalRecurrenceRule alloc] init];
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
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
if ((o = [theValues objectForKey: @"Organizer_Email"]) &&
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: o];
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
[person setPartStat: @"ACCEPTED"];
[self setOrganizer: person];
}
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])
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: [[[context activeUser] primaryIdentity] objectForKey: @"email"]];
[person setCn: [[context activeUser] cn]];
[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]])
{
NSMutableArray *attendees;
NSDictionary *attendee;
iCalPerson *person;
int status, i;
attendees = [NSMutableArray array];
for (i = 0; i < [o count]; i++)
{
// Each attendee has is a dictionary similar to this:
// { "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)
{
case 2:
[person setPartStat: @"TENTATIVE"];
break;
case 3:
[person setPartStat: @"ACCEPTED"];
break;
case 4:
[person setPartStat: @"DECLINED"];
break;
case 0:
case 5:
default:
{
[person setPartStat: @"NEEDS-ACTION"];
[person setRsvp: @"TRUE"];
}
break;
}
// FIXME: handle Attendee_Type
[attendees addObject: person];
}
[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
@@ -1,48 +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.
*/
#ifndef __ICALRECURRENCERULEACTIVESYNC_H__
#define __ICALRECURRENCERULEACTIVESYNC_H__
#import <NGCards/iCalRecurrenceRule.h>
@class NSDictionary;
@class NSString;
@class WOContext;
@interface iCalRecurrenceRule (ActiveSync)
- (NSString *) activeSyncRepresentationInContext:(WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
-399
View File
@@ -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.
*/
#import "iCalRecurrenceRule+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#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];
// 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly
type = 0;
if ([self frequency] == iCalRecurrenceFrequenceDaily)
{
type = 0;
// 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)];
}
else
{
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceWeekly)
{
iCalWeekOccurrences *occurrences;
int i, v;
type = 1;
occurrences = [[self byDayMask] weekDayOccurrences];
v = 0;
if (occurrences)
{
for (i = 0; i < 7; i++)
{
if (occurrences[0][i])
v += (1 << i);
}
}
else
{
// No byDayMask, we take the event's start date to compute the DayOfWeek
// 0 == Sunday, 6 == Saturday
v = (1 << [[self _adjustedStartDate] dayOfWeek]);
}
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, v];
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
}
else if ([self frequency] == iCalRecurrenceFrequenceMonthly)
{
if ([[self byDay] length])
{
int firstOccurrence;
iCalByDayMask *dm;
type = 3; // recurs monthly on the nth day
dm = [self byDayMask];
firstOccurrence = [dayMask firstOccurrence];
// Handle the case for "Last day of the month"
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]];
}
else if ([[self byMonthDay] count])
{
NSArray *days;
type = 2; // recurs monthly
days = [self byMonthDay];
if ([days count] > 0 && [[days objectAtIndex: 0] intValue] < 0)
{
// Last day of the month
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]];
}
else
{
// Unsupported rule in ActiveSync/Outlook. Rule that says "Repeat on the 7th and 8th of each month".
// FIXME
}
}
else
{
// Simple reccurrence rule of type "Monthly"
type = 2;
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%d</Recurrence_DayOfMonth>", t, [[self _adjustedStartDate] dayOfMonth]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
{
type = 6; // Yearly on the nth day
if ([[self flattenedValuesForKey: @"bymonth"] length])
{
if ([[self byDay] length])
{
int firstOccurrence;
iCalByDayMask *dm;
dm = [self byDayMask];
firstOccurrence = [dm firstOccurrence];
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,
[self flattenedValuesForKey: @"bymonth"]];
}
else
{
type = 5; // Yearly
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%@</Recurrence_DayOfMonth>", t,
[self flattenedValuesForKey: @"bymonthday"]];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%@</Recurrence_MonthOfYear>", t,
[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]];
}
}
[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]];
// Occurrences / Until
if ([self repeatCount])
{
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"%@:\">%@</Recurrence_Occurrences>", t,
[self flattenedValuesForKey: @"count"]];
}
else if ([self untilDate])
{
NSCalendarDate *date;
date = [self untilDate];
//ud = [[context activeUser] userDefaults];
//[date setTimeZone: [ud timeZone]];
[s appendFormat: @"<Recurrence_Until xmlns=\"%@:\">%@</Recurrence_Until>", t,
[date activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
[s appendString: @"</Recurrence>"];
return s;
}
//
//
//
- (void) _setByDayFromValues: (NSDictionary *) theValues
{
NSString *day;
id o;
unsigned int day_of_week;
int i, week_of_month;
o = [theValues objectForKey: @"Recurrence_DayOfWeek"];
// The documentation says WeekOfMonth must be between 1 and 5. The value
// 5 means "last week of month"
week_of_month = [[theValues objectForKey: @"Recurrence_WeekOfMonth"] intValue];
if (week_of_month > 4)
week_of_month = -1;
// We find the correct day of the week
day_of_week = [o intValue];
for (i = 0; i < 7; i++)
{
if ((1<<i) == day_of_week)
{
day_of_week = i;
break;
}
}
day = [self iCalRepresentationForWeekDay: i];
[self setSingleValue: [NSString stringWithFormat: @"%d%@",
week_of_month, day]
forKey: @"byday"];
}
- (void) _setByMonthFromValues: (NSDictionary *) theValues
{
unsigned int month_of_year;
month_of_year = [[theValues objectForKey: @"Recurrence_MonthOfYear"] intValue];
[self setSingleValue: [NSString stringWithFormat: @"%d", month_of_year]
forKey: @"bymonth"];
}
//
//
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
id o;
int recurrenceType;
recurrenceType = [[theValues objectForKey: @"Recurrence_Type"] intValue];
if ((o = [theValues objectForKey: @"Recurrence_Interval"]))
{
[self setRepeatInterval: [o intValue]];
}
else
[self setRepeatInterval: 1];
switch (recurrenceType)
{
//
// Daily
//
case 0:
[self setFrequency: iCalRecurrenceFrequenceDaily];
// Every weekday
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
[self setByDayMask: [iCalByDayMask byDayMaskWithWeekDays]];
}
break;
//
// Weekly
//
case 1:
[self setFrequency: iCalRecurrenceFrequenceWeekly];
// 42 == Every Monday, Wednesday and Friday, for example
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
iCalWeekOccurrences days;
unsigned int i, v;
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
v = [o intValue];
for (i = 0; i < 7; i++)
{
if (v & (1<<i))
days[i] = iCalWeekOccurrenceAll;
}
[self setByDayMask: [iCalByDayMask byDayMaskWithDays: days]];
}
break;
//
// Montly
//
case 2:
case 3:
[self setFrequency: iCalRecurrenceFrequenceMonthly];
// The 5th of every X month(s)
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
{
[self setValues: [NSArray arrayWithObject: o]
atIndex: 0 forKey: @"bymonthday"];
}
// The 3rd Thursay every X month(s)
else if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
[self _setByDayFromValues: theValues];
}
break;
//
// Yearly
//
case 5:
case 6:
default:
[self setFrequency: iCalRecurrenceFrequenceYearly];
// On April 19th
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
{
[self setValues: [NSArray arrayWithObject: o] atIndex: 0
forKey: @"bymonthday"];
[self _setByMonthFromValues: theValues];
}
else
{
// On the Second Wednesday of April
[self _setByDayFromValues: theValues];
[self _setByMonthFromValues: theValues];
}
break;
}
if ((o = [theValues objectForKey: @"Recurrence_Occurrences"]))
{
[self setRepeatCount: [o intValue]];
}
else if ((o = [theValues objectForKey: @"Recurrence_Until"]))
{
[self setUntilDate: [o calendarDate]];
}
}
@end
-44
View File
@@ -1,44 +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.
*/
#ifndef __ICALTIMEZONEACTIVESYNC_H__
#define __ICALTIMEZONEACTIVESYNC_H__
#import <NGCards/iCalTimeZone.h>
@class NSString;
@class WOContext;
@interface iCalTimeZone (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
@end
#endif
-184
View File
@@ -1,184 +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.
*/
#import "iCalTimeZone+ActiveSync.h"
#include <Foundation/NSArray.h>
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSString.h>
#import <NGCards/iCalByDayMask.h>
#import <NGCards/iCalTimeZonePeriod.h>
#include "NSData+ActiveSync.h"
struct SYSTEMTIME {
uint16_t wYear;
uint16_t wMonth;
uint16_t wDayOfWeek;
uint16_t wDay;
uint16_t wHour;
uint16_t wMinute;
uint16_t wSecond;
uint16_t wMilliseconds;
};
@interface iCalTimeZonePeriod (ActiveSync)
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData;
@end
@implementation iCalTimeZonePeriod (ActiveSync)
//
// FIXME - combine with iCalTimeZone+MAPIStore.m
//
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData
{
iCalRecurrenceRule *rrule;
NSArray *byMonth;
iCalByDayMask *mask;
NSCalendarDate *dateValue;
rrule = [self recurrenceRule];
byMonth = [rrule byMonth];
if ([byMonth count] > 0)
{
tzData->wYear = 0;
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
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;
}
}
}
@end
@implementation iCalTimeZone (ActiveSync)
//
// FIXME - combine with iCalTimeZone+MAPIStore.m
//
- (iCalTimeZonePeriod *) _mostRecentPeriodWithName: (NSString *) periodName
{
NSArray *periods;
iCalTimeZonePeriod *period;
NSUInteger max;
periods = [self childrenWithTag: periodName];
max = [periods count];
if (max > 0)
{
periods = [periods sortedArrayUsingSelector: @selector (compare:)];
period = (iCalTimeZonePeriod *) [periods objectAtIndex: (max - 1)];
}
else
period = nil;
return period;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
iCalTimeZonePeriod *period;
NSMutableData *bytes;
uint32_t lBias;
uint32_t lStandardBias;
uint32_t lDaylightBias;
//uint16_t wStandardYear;
struct SYSTEMTIME stStandardDate;
//uint16_t wDaylightYear;
struct SYSTEMTIME stDaylightDate = {0,0,0,0,0,0,0,0};
char standardName[64], daylightName[64];
bytes = [NSMutableData data];
memset(standardName, 0, 64);
memset(daylightName, 0, 64);
lStandardBias = 0;
period = [self _mostRecentPeriodWithName: @"STANDARD"];
lBias = -[period secondsOffsetFromGMT] / 60;
[period _fillTZDate: &stStandardDate];
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;
}
// We build the timezone
[bytes appendBytes: &lBias length: 4];
[bytes appendBytes: standardName length: 64];
[bytes appendBytes: &stStandardDate length: 16];
[bytes appendBytes: &lStandardBias length: 4];
[bytes appendBytes: daylightName length: 64];
[bytes appendBytes: &stDaylightDate length: 16];
[bytes appendBytes: &lDaylightBias length: 4];
return [bytes activeSyncRepresentationInContext: context];
}
@end
-46
View File
@@ -1,46 +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.
*/
#ifndef __ICALTODOACTIVESYNC_H__
#define __ICALTODOACTIVESYNC_H__
#import <NGCards/iCalToDo.h>
@class NSString;
@class WOContext;
@interface iCalToDo (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
-314
View File
@@ -1,314 +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.
*/
#import "iCalToDo+ActiveSync.h"
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#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;
s = [NSMutableString string];
// Complete
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
// DateCompleted
if ((o = [self completed]))
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
// Start date
if ((o = [self startDate]))
{
[s appendFormat: @"<StartDate xmlns=\"Tasks:\">%@</StartDate>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<UTCStartDate xmlns=\"Tasks:\">%@</UTCStartDate>", [o activeSyncRepresentationInContext: context]];
}
// Due date
if ((o = [self due]))
{
[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];
if ([o isEqualToString: @"9"])
v = 0;
else if ([o isEqualToString: @"1"])
v = 2;
else
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];
}
// 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])
[s appendFormat: @"<Subject xmlns=\"Tasks:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
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>"];
}
}
return s;
}
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
id o;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
// FIXME: merge with iCalEvent
if ((o = [theValues objectForKey: @"Subject"]))
[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 ([[theValues objectForKey: @"Complete"] intValue] &&
((o = [theValues objectForKey: @"DateCompleted"])) )
{
iCalDateTime *completed;
o = [o calendarDate];
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
[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];
[due setDateTime: o];
}
// 2 == high, 1 == normal, 0 == low
if ((o = [theValues objectForKey: @"Importance"]))
{
if ([o intValue] == 2)
[self setPriority: @"1"];
else if ([o intValue] == 1)
[self setPriority: @"5"];
else
[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
-3
View File
@@ -1,3 +0,0 @@
{
requires = ( MAIN, Appointments, Contacts, Mailer );
}
+1 -54
View File
@@ -1,57 +1,4 @@
#
#
# Keep only one of those vhost definition, comment out the other one
#
#
# for https
# don't forget to add a Listen parameter for port 8843:
# Listen 8843
<VirtualHost *:8843>
ServerName YOUR.SERVER.NAME
SSLEngine on
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite HIGH:MEDIUM:!ADH:!aNULL:!eNULL:!NULL
SSLCertificateFile /path/to/your/cert/cert.pem
SSLCertificateChainFile /path/to/your/cert/cert-chain-file.pem
SSLCertificateKeyFile /path/to/your/key/file.key
RewriteEngine Off
ProxyRequests Off
SetEnv proxy-nokeepalive 1
ProxyPreserveHost On
ProxyPassInterpolateEnv On
ProxyPass /principals http://127.0.0.1:20000/SOGo/dav/ interpolate
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
<Location />
<IfVersion < 2.4>
Order deny,allow
Allow from all
</IfVersion>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
</Location>
<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-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
</Proxy>
ErrorLog /var/log/apache2/ab-error.log
CustomLog /var/log/apache2/ab-access.log combined
</VirtualHost>
# plain http
# Same here, don't forget to add a Listen parameter for port 8800:
# Listen 8800
# use *:8843 for SSL
<VirtualHost *:8800>
RewriteEngine Off
ProxyRequests Off
+15 -60
View File
@@ -2,17 +2,13 @@ Alias /SOGo.woa/WebServerResources/ \
/usr/lib/GNUstep/SOGo/WebServerResources/
Alias /SOGo/WebServerResources/ \
/usr/lib/GNUstep/SOGo/WebServerResources/
AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
/usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
<Directory /usr/lib/GNUstep/SOGo/>
AllowOverride None
<IfVersion < 2.4>
Order deny,allow
Allow from all
</IfVersion>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
Order deny,allow
Allow from all
# 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.
@@ -22,43 +18,24 @@ 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>
<LocationMatch "^/SOGo/so/ControlPanel/Products/.*UI/Resources/.*\.(jpg|png|gif|css|js)">
SetHandler default-handler
</LocationMatch>
## 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
## below.
#
## For full proxy-side authentication:
#<Location /SOGo>
# AuthType XXX
# Require valid-user
# SetEnv proxy-nokeepalive 1
# Allow from all
#</Location>
#
## For proxy-side authentication only for CardDAV and GroupDAV from external
## clients:
#<Location /SOGo/dav>
# AuthType XXX
# Require valid-user
# SetEnv proxy-nokeepalive 1
# Allow from all
#</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,35 +46,19 @@ SetEnv proxy-nokeepalive 1
# Allow from your-cas-host-addr
# </Proxy>
# Redirect / to /SOGo
#RedirectMatch ^/$ https://mail.yourdomain.com/SOGo
# Enable to use Microsoft ActiveSync support
# Note that you MUST have many sogod workers to use ActiveSync.
# See the SOGo Installation and Configuration guide for more details.
#
#ProxyPass /Microsoft-Server-ActiveSync \
# 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
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
<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 set "x-webobjects-remote-user" "%{REMOTE_USER}e"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
</IfModule>
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
@@ -105,9 +66,3 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
Allow from all
</Proxy>
# 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>
Loaded 100 of 3732 files, more files were not shown because too many files have changed in this diff. Show more