Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
5e82c6211e | |||
6d90966f28 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
db
|
|
98
README.md
98
README.md
@ -1,12 +1,90 @@
|
|||||||
Update, run, inspect and stop server:
|
# Vorraussetzungen
|
||||||
```
|
|
||||||
docker-compose pull
|
|
||||||
docker-compose up -d
|
|
||||||
docker-compose logs -t -f
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
Login to roundcube
|
|
||||||
```
|
|
||||||
docker-compose exec roundcube sh
|
|
||||||
|
|
||||||
|
Folgendes wird in Linux gemacht (es ist aber nicht zwingend ein eigenes Linux erforderlich):
|
||||||
|
|
||||||
|
* Erstellen und bearbeiten von Dateien (Shell oder GUI)
|
||||||
|
* Starten von Programmen auf der Commandline
|
||||||
|
|
||||||
|
## Installation in Ubuntu Linux
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
sudo apt install docker-compose
|
||||||
|
sudo adduser <user> docker # allow docker as user
|
||||||
|
su <user> # relogin or reboot system to apply new group
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ohne Linux
|
||||||
|
|
||||||
|
### Verwenden einer virtuellen Maschine mit Linux
|
||||||
|
|
||||||
|
Z.B. mit _Virtual Box_ kann ein virtueller Rechner aufgesetzt werden.
|
||||||
|
|
||||||
|
### Verbinden über ssh auf einen Linux-Rechner
|
||||||
|
|
||||||
|
Wer kein eigenes Linux hat, kann sich über ssh mit einem Linux-Rechner verbinden, z.B. mit _Putty_. In diesem Fall ist es gut, wenn man auch Dateien auf der Commandline editieren kann.
|
||||||
|
|
||||||
|
### Verwenden von Windows Subsystem for Linux
|
||||||
|
|
||||||
|
Das geht wohl auch irgendwie, aber nicht besonders gut.
|
||||||
|
|
||||||
|
# Hello-World Projekt erstellen
|
||||||
|
|
||||||
|
## Mit git
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
git clone https://git.hilie.de/toptica/docker-compose-workshop.git hello-world
|
||||||
|
cd hello-world
|
||||||
|
git checkout hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ohne git
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
mkdir hello-world
|
||||||
|
cd hello-world
|
||||||
|
vi docker-compose.yaml # Datei »docker-compose.yaml« erstellen und bearbeiten
|
||||||
|
```
|
||||||
|
|
||||||
|
Inhalt für docker-compose.yaml:
|
||||||
|
``` yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
hello_world:
|
||||||
|
image: hello-world:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
# Hello-World Projekt ausführen
|
||||||
|
``` bash
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
Folgende Ausgabe sollte unter anderem so ähnlich erscheinen:
|
||||||
|
``` bash
|
||||||
|
Recreating dockercompose_hello_world_1 ...
|
||||||
|
Recreating dockercompose_hello_world_1 ... done
|
||||||
|
Attaching to dockercompose_hello_world_1
|
||||||
|
hello_world_1 |
|
||||||
|
hello_world_1 | Hello from Docker!
|
||||||
|
hello_world_1 | This message shows that your installation appears to be working correctly.
|
||||||
|
hello_world_1 |
|
||||||
|
hello_world_1 | To generate this message, Docker took the following steps:
|
||||||
|
hello_world_1 | 1. The Docker client contacted the Docker daemon.
|
||||||
|
hello_world_1 | 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||||
|
hello_world_1 | (amd64)
|
||||||
|
hello_world_1 | 3. The Docker daemon created a new container from that image which runs the
|
||||||
|
hello_world_1 | executable that produces the output you are currently reading.
|
||||||
|
hello_world_1 | 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||||
|
hello_world_1 | to your terminal.
|
||||||
|
hello_world_1 |
|
||||||
|
hello_world_1 | To try something more ambitious, you can run an Ubuntu container with:
|
||||||
|
hello_world_1 | $ docker run -it ubuntu bash
|
||||||
|
hello_world_1 |
|
||||||
|
hello_world_1 | Share images, automate workflows, and more with a free Docker ID:
|
||||||
|
hello_world_1 | https://hub.docker.com/
|
||||||
|
hello_world_1 |
|
||||||
|
hello_world_1 | For more examples and ideas, visit:
|
||||||
|
hello_world_1 | https://docs.docker.com/get-started/
|
||||||
|
hello_world_1 |
|
||||||
|
dockercompose_hello_world_1 exited with code 0
|
||||||
```
|
```
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
roundcube:
|
|
||||||
image: instrumentisto/roundcube:1.4.7-fpm
|
|
||||||
expose:
|
|
||||||
- "9000"
|
|
||||||
volumes:
|
|
||||||
- app-volume:/app
|
|
||||||
- ./db:/var/db
|
|
||||||
- ./roundcube.config.php:/app/config/config.inc.php:ro
|
|
||||||
- ./plugins/identity_smtp:/app/plugins/identity_smtp
|
|
||||||
- ./plugins/carddav:/app/plugins/carddav
|
|
||||||
- ./plugins/managesieve/config.inc.php:/app/plugins/managesieve/config.inc.php
|
|
||||||
|
|
||||||
nginx:
|
|
||||||
image: nginx:1.16.0-alpine
|
|
||||||
depends_on:
|
|
||||||
- roundcube
|
|
||||||
ports:
|
|
||||||
- "8081:80"
|
|
||||||
volumes:
|
|
||||||
- app-volume:/var/www
|
|
||||||
- ./fpm.nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
app-volume:
|
|
@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
root /var/www/html;
|
|
||||||
index index.php;
|
|
||||||
charset utf-8;
|
|
||||||
|
|
||||||
location = /favicon.ico {
|
|
||||||
root /var/www/html/skins/larry/images;
|
|
||||||
access_log off;
|
|
||||||
log_not_found off;
|
|
||||||
expires max;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /robots.txt {
|
|
||||||
allow all;
|
|
||||||
access_log off;
|
|
||||||
log_not_found off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ index.php;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ /\.ht {
|
|
||||||
deny all;
|
|
||||||
access_log off;
|
|
||||||
log_not_found off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~* \.php$ {
|
|
||||||
try_files $uri =404;
|
|
||||||
include fastcgi_params;
|
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
||||||
fastcgi_pass roundcube:9000;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
3
plugins/carddav/.gitignore
vendored
3
plugins/carddav/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
config.inc.php
|
|
||||||
composer.phar
|
|
||||||
/vendor
|
|
@ -1,52 +0,0 @@
|
|||||||
Changes from 0.7.0 to 0.8.0:
|
|
||||||
* Implement sync_token support for less overhead when syncing
|
|
||||||
* Use XPath XML parsing instead of self-rolled functions
|
|
||||||
* Automatically detect all addressbooks on server
|
|
||||||
* Only use sync methods the server advertises
|
|
||||||
* many small changes
|
|
||||||
|
|
||||||
Changes from 0.6.1 to 0.7.0:
|
|
||||||
* merge branch: cache
|
|
||||||
* support caching of entire addressbooks, thus speeding up repetetive queries
|
|
||||||
* add localizations: italian, french, swedish, hungarian
|
|
||||||
* improvements in handling multiple addressbooks
|
|
||||||
* improvements in handling different CardDAV servers
|
|
||||||
|
|
||||||
Changes from 0.6.0 to 0.6.1:
|
|
||||||
* merge branch: multipleaddressbooks
|
|
||||||
* support multiple authorization header elements, patch by Michael Stilkerich
|
|
||||||
* adapt config file and its handling to new multiple addressbook feature
|
|
||||||
* fix FS#25 attaching photo
|
|
||||||
* fix FS#27 use surname lastname if no nickname provided
|
|
||||||
* fix FS#29 displayname/nickname handling
|
|
||||||
|
|
||||||
Changes from 0.4.2 to 0.6.0:
|
|
||||||
* add group support
|
|
||||||
* faster vcard retrieval
|
|
||||||
* vcard parsing with library
|
|
||||||
* support for configuration file
|
|
||||||
* support full-featured addressbook of RC 0.6
|
|
||||||
|
|
||||||
Changes from 0.4.1 to 0.4.2:
|
|
||||||
* add some debug entries
|
|
||||||
* fix FS#7 - case-insensitive Authentication headers (Basic vs. basic, Digest vs. digest)
|
|
||||||
|
|
||||||
Changes from 0.4.0 to 0.4.1:
|
|
||||||
* use PHP HTTP Client class for the whole HTTP layer handling. This speeds up processing from taking 15s to being "snappy".
|
|
||||||
|
|
||||||
Changes from 0.3.1 to 0.4.0:
|
|
||||||
* check if PHP_VERSION >= 5.3.0 and display an error message in the preferences tab if too old.
|
|
||||||
This is because of https://bugs.php.net/bug.php?id=46035
|
|
||||||
* fix FS#14 - add function get_name
|
|
||||||
* do not use + for delimiters, but _ as rcm 0.6 will substitute + for _
|
|
||||||
|
|
||||||
Changes from 0.3.0 to 0.3.1:
|
|
||||||
|
|
||||||
* fix FS#10 - incomplete searchresults now complete
|
|
||||||
* fixes FS#11 - do not use ob_* functions but a custom error handler to catch fopen errors
|
|
||||||
* make password inputfield a password html-element to prevent shouldersurfing of password
|
|
||||||
* make size of url input field as long as the value, but at least 40
|
|
||||||
* remove stray write_log in myErrorHandler
|
|
||||||
* make list_records return false instead of an empty result list if a search for an entry returned no results
|
|
||||||
* use <href> tag for ID parsing instead of UID parameter in vCard
|
|
||||||
* try harder to authenticate against server - especially useful for PHP 5.2.x
|
|
@ -1,37 +0,0 @@
|
|||||||
0. Log out of Roundcube! This is necessary for proper setup of the databases later.
|
|
||||||
|
|
||||||
1a. Download the last release of RCMCardDAV here:
|
|
||||||
https://github.com/blind-coder/rcmcarddav/releases/tag/v3.0.3
|
|
||||||
Extract the archive and rename the extracted directory to 'carddav'.
|
|
||||||
|
|
||||||
1b. Copy/Clone the whole RCMCardDAV plugin directory to roundcubemail/plugins/ and rename
|
|
||||||
the directory to 'carddav'.
|
|
||||||
|
|
||||||
2. Only if you are installing a git clone, change to the directory
|
|
||||||
roundcubemail/plugins/carddav/ and install the dependencies using composer:
|
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
|
||||||
php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
|
||||||
php composer-setup.php
|
|
||||||
php -r "unlink('composer-setup.php');"
|
|
||||||
php composer.phar install
|
|
||||||
|
|
||||||
3. Change to the plugin directory roundcubemail/plugins/carddav and copy the
|
|
||||||
file 'config.inc.php.dist' to 'config.inc.php' to create the initial plugin
|
|
||||||
configuration file.
|
|
||||||
|
|
||||||
4. If necessary, customize the default plugin settings in the file created in
|
|
||||||
step 3.
|
|
||||||
|
|
||||||
5. Make sure that the file and directory ownership match the user which is used
|
|
||||||
to run your web server, e.g.:
|
|
||||||
chown -R wwwrun roundcubemail/plugins/carddav
|
|
||||||
chgrp -R nogroup roundcubemail/plugins/carddav
|
|
||||||
|
|
||||||
6. Install the curl and mbstring php extensions if not already present:
|
|
||||||
apt-get install php7.0-{mbstring,curl} # on Debian
|
|
||||||
|
|
||||||
7. Add 'carddav' to the $rcmail_config['plugins'] array in
|
|
||||||
roundcubemail/config/main.inc.php
|
|
||||||
|
|
||||||
8. Login to Roundcube and set-up your first CardDAV address book by accessing
|
|
||||||
'Settings -> Settings -> CardDAV'
|
|
@ -1,5 +0,0 @@
|
|||||||
- Clone the repository:
|
|
||||||
`cd roundcube/plugins && git clone https://github.com/blind-coder/rcmcarddav.git carddav`
|
|
||||||
- Install dependencies:
|
|
||||||
- Install composer as per the documentation: https://getcomposer.org/download/
|
|
||||||
- Run `php composer.phar install`
|
|
@ -1,339 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
@ -1,47 +0,0 @@
|
|||||||
RCMCardDAV
|
|
||||||
==========
|
|
||||||
|
|
||||||
CardDAV plugin for the RoundCube Webmailer
|
|
||||||
|
|
||||||
Upgrading from 1.0
|
|
||||||
==================
|
|
||||||
|
|
||||||
There is no upgrade path from the 1.0 version. You need to manually remove RCMCardDAV 1.0, drop its tables from your database and start with a fresh installation.
|
|
||||||
|
|
||||||
Upgrading from 2.0.x
|
|
||||||
==================
|
|
||||||
|
|
||||||
There is no supported upgrade path from the 2.0.x version. You need to manually remove RCMCardDAV 2.0.x, drop its tables from your database and start with a fresh installation.
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
============
|
|
||||||
RCMCardDAV requires at least PHP 5.6.18. Older versions might work if the version check is disabled using the `$prefs['_GLOBAL']['suppress_version_warning']` configuration entry, but this is unsupported.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
RCMCardDAV can be installed via composer, from a release tarball or from a git clone. This list is in increasing difficulty, with composer being the easiest method.
|
|
||||||
|
|
||||||
Please note that due to version incompatibilities of depending libraries, this plugin might be incompatible to Kolabs calendar plugin. There is a compatible version available here: `http://git.faster-it.de/roundcube_calendar/`.
|
|
||||||
|
|
||||||
Intallation steps:
|
|
||||||
- Log out of Roundcube!
|
|
||||||
This is important because RCMCardDAV runs its database initialisation / update procedure only when a user logs in!
|
|
||||||
- Get RCMCardDAV
|
|
||||||
- Via composer:
|
|
||||||
- Add `"roundcube/carddav": "dev-master"` to your composer.json file and install with `php composer.phar install`.
|
|
||||||
- Via release tarball:
|
|
||||||
- Download and extract the release tarball into `roundcube/plugins` directory and rename the extracted directory to `carddav`. The tarball contains all necessary dependencies and does not need composer.
|
|
||||||
- Via git:
|
|
||||||
- Please do not do not do this unless you have a very good reason for it! Check the file [INSTALLFROMGIT.md](INSTALLFROMGIT.md) for instructions.
|
|
||||||
- Configure RCMCardDAV
|
|
||||||
If you want to configure preset addressbooks for your users, copy the file `config.inc.php.dist` to `config.inc.php` and edit it as you need.
|
|
||||||
- Make sure that the files and directories are owned by the user and group that your webserver runs as. For Debian GNU/Linux that would be:
|
|
||||||
`chown -R www-data:www-data roundcubemail/plugins/carddav`
|
|
||||||
- Install the curl php extension if not already present:
|
|
||||||
`sudo apt-get install php5-curl`
|
|
||||||
- Enable RCMCardDAV in Roundcube:
|
|
||||||
Open the file `roundcube/config/config.inc.php` and add `carddav` to the array `$config['plugins']`.
|
|
||||||
- Login to Roundcube and setup your addressbook by navigation to the Settings page and click on CardDAV.
|
|
||||||
|
|
||||||
In case of errors, check the files `roundcube/logs/*`.
|
|
@ -1,684 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
RCM CardDAV Plugin
|
|
||||||
Copyright (C) 2011-2016 Benjamin Schieder <rcmcarddav@wegwerf.anderdonau.de>,
|
|
||||||
Michael Stilkerich <ms@mike2k.de>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
class carddav extends rcube_plugin
|
|
||||||
{
|
|
||||||
private static $helper;
|
|
||||||
|
|
||||||
// the dummy task is used by the calendar plugin, which requires
|
|
||||||
// the addressbook to be initialized
|
|
||||||
public $task = 'addressbook|login|mail|settings|dummy';
|
|
||||||
|
|
||||||
public function checkMigrations(){
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
|
|
||||||
$db_backend = "unknown";
|
|
||||||
|
|
||||||
switch ($dbh->db_provider){
|
|
||||||
case "mysql":
|
|
||||||
$db_backend = "mysql";
|
|
||||||
break;
|
|
||||||
case "sqlite":
|
|
||||||
$db_backend = "sqlite3";
|
|
||||||
break;
|
|
||||||
case "pgsql":
|
|
||||||
case "postgres":
|
|
||||||
$db_backend = "postgres";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($db_backend == "unknown"){
|
|
||||||
rcmail::write_log("carddav", "Unknown database backend: ".$dbh->db_provider);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# first initialize the carddav_migrations table if it doesn't exist.
|
|
||||||
/*
|
|
||||||
$query = file_get_contents(dirname(__FILE__)."/dbinit/".$db_backend.".sql");
|
|
||||||
if (strlen($query) > 0){
|
|
||||||
$query = str_replace("TABLE_PREFIX", $config->get('db_prefix', ""), $query);
|
|
||||||
$dbh->query($query);
|
|
||||||
rcmail::write_log("carddav", "Processed initialization of carddav_migrations table");
|
|
||||||
} else {
|
|
||||||
rcmail::write_log("carddav", "Can't find migration: /dbinit/".$db_backend.".sql");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
$config = rcmail::get_instance()->config;
|
|
||||||
$migrations = array_diff(scandir(dirname(__FILE__)."/dbmigrations/"), array('..', '.'));
|
|
||||||
$mignew = array();
|
|
||||||
foreach ($migrations as $k => $v){
|
|
||||||
$mignew[] = $v;
|
|
||||||
}
|
|
||||||
$migrations = $mignew;
|
|
||||||
$qmarks = "?";
|
|
||||||
for ($i=1;$i<count($migrations);$i++){
|
|
||||||
$qmarks .= ",?";
|
|
||||||
}
|
|
||||||
|
|
||||||
$dbh->set_option('ignore_key_errors', true);
|
|
||||||
$sql_result = $dbh->query('SELECT * FROM '.
|
|
||||||
$dbh->table_name('carddav_migrations') .
|
|
||||||
' WHERE filename IN ('.$qmarks.');', $migrations);
|
|
||||||
|
|
||||||
if ($sql_result){
|
|
||||||
while ($processed = $dbh->fetch_assoc($sql_result)) {
|
|
||||||
if(($key = array_search($processed['filename'], $migrations)) !== false) {
|
|
||||||
unset($migrations[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$dbh->set_option('ignore_key_errors', null);
|
|
||||||
|
|
||||||
foreach ($migrations as $migration) {
|
|
||||||
rcmail::write_log('carddav', "In migration: ".$migration);
|
|
||||||
$queries_raw = file_get_contents(dirname(__FILE__)."/dbmigrations/".$migration."/".$db_backend.".sql");
|
|
||||||
$match_count = preg_match_all('/(.+?;)/s', $queries_raw, $matches);
|
|
||||||
rcmail::write_log('carddav', 'Found '.$match_count.' matches');
|
|
||||||
if($match_count > 0){
|
|
||||||
foreach ($matches[0] as $query){ // array will have two elements, each holding all queries. Only iterate over one of them
|
|
||||||
if (strlen($query) > 0){
|
|
||||||
$query = str_replace("TABLE_PREFIX", $config->get('db_prefix', ""), $query);
|
|
||||||
$dbh->query($query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$dbh->query("INSERT INTO ".$dbh->table_name("carddav_migrations")." (filename) VALUES (?)", $migration);
|
|
||||||
}else{
|
|
||||||
rcmail::write_log('carddav', "Did not match any instructions from migration ".$migration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function init()
|
|
||||||
{{{
|
|
||||||
$this->rc = rcmail::get_instance();
|
|
||||||
$tasks = explode('|', $this->task);
|
|
||||||
|
|
||||||
// Since other plugins may also use the Sabre library
|
|
||||||
// In order to avoid version conflicts between Sabre libraries
|
|
||||||
// which might be used by other plugins
|
|
||||||
// It is better to restrict the loading of Sabre library
|
|
||||||
// under necessary tasks
|
|
||||||
if(!in_array($this->rc->task, $tasks))
|
|
||||||
return;
|
|
||||||
else {
|
|
||||||
require_once('carddav_backend.php');
|
|
||||||
require_once('carddav_discovery.php');
|
|
||||||
require_once('carddav_common.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$helper = new carddav_common('BACKEND: ');
|
|
||||||
|
|
||||||
$this->add_hook('addressbooks_list', array($this, 'address_sources'));
|
|
||||||
$this->add_hook('addressbook_get', array($this, 'get_address_book'));
|
|
||||||
|
|
||||||
$this->add_hook('preferences_list', array($this, 'cd_preferences'));
|
|
||||||
$this->add_hook('preferences_save', array($this, 'cd_save'));
|
|
||||||
$this->add_hook('preferences_sections_list',array($this, 'cd_preferences_section'));
|
|
||||||
|
|
||||||
$this->add_hook('login_after',array($this, 'checkMigrations'));
|
|
||||||
$this->add_hook('login_after',array($this, 'init_presets'));
|
|
||||||
|
|
||||||
if(!array_key_exists('user_id', $_SESSION))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// use this address book for autocompletion queries
|
|
||||||
// (maybe this should be configurable by the user?)
|
|
||||||
$config = rcmail::get_instance()->config;
|
|
||||||
$sources = (array) $config->get('autocomplete_addressbooks', array('sql'));
|
|
||||||
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
$sql_result = $dbh->query('SELECT id FROM ' .
|
|
||||||
$dbh->table_name('carddav_addressbooks') .
|
|
||||||
' WHERE user_id=? AND active=1',
|
|
||||||
$_SESSION['user_id']);
|
|
||||||
|
|
||||||
while ($abookrow = $dbh->fetch_assoc($sql_result)) {
|
|
||||||
$abookname = "carddav_" . $abookrow['id'];
|
|
||||||
if (!in_array($abookname, $sources)) {
|
|
||||||
$sources[] = $abookname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$config->set('autocomplete_addressbooks', $sources);
|
|
||||||
$skin_path = $this->local_skin_path();
|
|
||||||
$this->include_stylesheet($skin_path . '/carddav.css');
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function init_presets()
|
|
||||||
{{{
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
$prefs = carddav_common::get_adminsettings();
|
|
||||||
|
|
||||||
// migrate old settings
|
|
||||||
carddav_backend::migrateconfig();
|
|
||||||
|
|
||||||
// read existing presets from DB
|
|
||||||
$sql_result = $dbh->query('SELECT * FROM ' .
|
|
||||||
$dbh->table_name('carddav_addressbooks') .
|
|
||||||
' WHERE user_id=? AND presetname is not null',
|
|
||||||
$_SESSION['user_id']);
|
|
||||||
|
|
||||||
$existing_presets = array( );
|
|
||||||
while ($abookrow = $dbh->fetch_assoc($sql_result)) {
|
|
||||||
$pn = $abookrow['presetname'];
|
|
||||||
if(!array_key_exists($pn,$existing_presets)) {
|
|
||||||
$existing_presets[$pn] = array();
|
|
||||||
}
|
|
||||||
$existing_presets[$pn][] = $abookrow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add not existing preset addressbooks
|
|
||||||
foreach($prefs as $presetname => $preset) {
|
|
||||||
if($presetname === '_GLOBAL') continue;
|
|
||||||
|
|
||||||
// addressbooks exist for this preset => update settings
|
|
||||||
if(array_key_exists($presetname, $existing_presets)) {
|
|
||||||
if(is_array($preset['fixed'])) {
|
|
||||||
// update all existing addressbooks for this preset
|
|
||||||
foreach($existing_presets[$presetname] as $abookrow) {
|
|
||||||
// decrypt password so that the comparison works
|
|
||||||
$abookrow['password'] = self::$helper->decrypt_password($abookrow['password']);
|
|
||||||
|
|
||||||
// update: only admin fix keys, only if it's fixed
|
|
||||||
// otherwise there may be user changes that should not be destroyed
|
|
||||||
$pa = array();
|
|
||||||
|
|
||||||
foreach($preset['fixed'] as $k) {
|
|
||||||
if(array_key_exists($k, $abookrow) && array_key_exists($k,$preset)) {
|
|
||||||
|
|
||||||
// only update the name if it is used
|
|
||||||
if($k === 'name') {
|
|
||||||
if(!$preset['carddav_name_only']) {
|
|
||||||
$fullname = $abookrow['name'];
|
|
||||||
$cnpos = strpos($fullname, ' (');
|
|
||||||
if($cnpos === FALSE && strcmp($preset['name'],$fullname)!==0) {
|
|
||||||
$pa['name'] = $preset['name'];
|
|
||||||
} else if($cnpos !== FALSE && strcmp($preset['name'],substr($fullname,0,$cnpos))!==0) {
|
|
||||||
$pa['name'] = $preset['name'] . substr($fullname, $cnpos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ($abookrow[$k] != $preset[$k]) {
|
|
||||||
$pa[$k] = $preset[$k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only update if something changed
|
|
||||||
if(count($pa)===0) continue;
|
|
||||||
|
|
||||||
self::update_abook($abookrow['id'],$pa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($existing_presets[$presetname]);
|
|
||||||
|
|
||||||
} else { // create new
|
|
||||||
$preset['presetname'] = $presetname;
|
|
||||||
$preset['password'] = self::$helper->encrypt_password($preset['password']);
|
|
||||||
$abname = $preset['name'];
|
|
||||||
|
|
||||||
$discovery = new carddav_discovery();
|
|
||||||
$srvs = $discovery->find_addressbooks($preset['url'], $preset['username'], $preset['password']);
|
|
||||||
|
|
||||||
if(is_array($srvs)) {
|
|
||||||
foreach($srvs as $srv){
|
|
||||||
if($srv['name']) {
|
|
||||||
if($preset['carddav_name_only'])
|
|
||||||
$preset['name'] = $srv['name'];
|
|
||||||
else
|
|
||||||
$preset['name'] = "$abname (" . $srv['name'] . ')';
|
|
||||||
} else {
|
|
||||||
$preset['name'] = $abname;
|
|
||||||
}
|
|
||||||
$preset['url'] = $srv['href'];
|
|
||||||
self::insert_abook($preset);
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete existing preset addressbooks that where removed by admin
|
|
||||||
foreach($existing_presets as $ep) {
|
|
||||||
foreach($ep as $abookrow) {
|
|
||||||
self::delete_abook($abookrow['id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function address_sources($p)
|
|
||||||
{{{
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
$prefs = carddav_common::get_adminsettings();
|
|
||||||
|
|
||||||
$sql_result = $dbh->query('SELECT id,name,presetname FROM ' .
|
|
||||||
$dbh->table_name('carddav_addressbooks') .
|
|
||||||
' WHERE user_id=? AND active=1',
|
|
||||||
$_SESSION['user_id']);
|
|
||||||
|
|
||||||
while ($abookrow = $dbh->fetch_assoc($sql_result)) {
|
|
||||||
$ro = false;
|
|
||||||
if($abookrow['presetname'] && $prefs[$abookrow['presetname']]['readonly'])
|
|
||||||
$ro = true;
|
|
||||||
|
|
||||||
$p['sources']["carddav_".$abookrow['id']] = array(
|
|
||||||
'id' => "carddav_".$abookrow['id'],
|
|
||||||
'name' => $abookrow['name'],
|
|
||||||
'groups' => true,
|
|
||||||
'autocomplete' => true,
|
|
||||||
'readonly' => $ro,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $p;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function get_address_book($p)
|
|
||||||
{{{
|
|
||||||
if (preg_match(";^carddav_(\d+)$;", $p['id'], $match)){
|
|
||||||
$p['instance'] = new carddav_backend($match[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $p;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
private static function process_cd_time($refresht)
|
|
||||||
{{{
|
|
||||||
if(preg_match('/^(\d+)(:([0-5]?\d))?(:([0-5]?\d))?$/', $refresht, $match)) {
|
|
||||||
$refresht = sprintf("%02d:%02d:%02d", $match[1],
|
|
||||||
count($match)>3 ? $match[3] : 0,
|
|
||||||
count($match)>5 ? $match[5] : 0);
|
|
||||||
} else {
|
|
||||||
$refresht = '01:00:00';
|
|
||||||
}
|
|
||||||
return $refresht;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
private static function no_override($pref, $abook, $prefs)
|
|
||||||
{{{
|
|
||||||
$pn = $abook['presetname'];
|
|
||||||
if(!$pn) return false;
|
|
||||||
|
|
||||||
// never enable user change for preset URLs
|
|
||||||
if($pref === 'url') return true;
|
|
||||||
|
|
||||||
if(!is_array($prefs[$pn])) return false;
|
|
||||||
if(!is_array($prefs[$pn]['fixed'])) return false;
|
|
||||||
|
|
||||||
return in_array($pref,$prefs[$pn]['fixed']);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a setting block for one address book for the preference page.
|
|
||||||
*/
|
|
||||||
private function cd_preferences_buildblock($blockheader,$abook,$prefs)
|
|
||||||
{{{
|
|
||||||
$abookid = $abook['id'];
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
|
|
||||||
if (self::no_override('active', $abook, $prefs)) {
|
|
||||||
$content_active = $prefs[$abook['presetname']] ? $this->gettext('cd_enabled') : $this->gettext('cd_disabled');
|
|
||||||
} else {
|
|
||||||
// check box for activating
|
|
||||||
$checkbox = new html_checkbox(array('name' => $abookid.'_cd_active', 'value' => 1));
|
|
||||||
$content_active = $checkbox->show($abook['active']?1:0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::no_override('use_categories', $abook, $prefs) || $abook['id'] !== "new") {
|
|
||||||
$content_use_categories = $abook['use_categories'] ? $this->gettext('cd_enabled') : $this->gettext('cd_disabled');
|
|
||||||
} else {
|
|
||||||
// check box for use categories
|
|
||||||
$checkbox = new html_checkbox(array('name' => $abookid.'_cd_use_categories', 'value' => 1));
|
|
||||||
$content_use_categories = $checkbox->show($abook['use_categories']?1:0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::no_override('username', $abook, $prefs)) {
|
|
||||||
// %V parses username for macosx, replaces periods and @ by _, work around bugs in contacts.app
|
|
||||||
$content_username = $abook['username'] === '%V' ? str_replace('@','_', str_replace('.','_',$_SESSION['username'])) : $abook['username'] === '%u' ? $_SESSION['username'] : $abook['username'] === '%l' ? $rcmail->user->get_username('local') : $abook['username'];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// input box for username
|
|
||||||
$input = new html_inputfield(array('name' => $abookid.'_cd_username', 'type' => 'text', 'autocomplete' => 'off', 'value' => $abook['username']));
|
|
||||||
$content_username = $input->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::no_override('password', $abook, $prefs)) {
|
|
||||||
$content_password = "***";
|
|
||||||
} else {
|
|
||||||
// input box for password
|
|
||||||
$input = new html_inputfield(array('name' => $abookid.'_cd_password', 'type' => 'password', 'autocomplete' => 'off', 'value' => ''));
|
|
||||||
$content_password = $input->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::no_override('url', $abook, $prefs)) {
|
|
||||||
$content_url = str_replace("%u", $abook['username'], $abook['url']);
|
|
||||||
} else {
|
|
||||||
// input box for URL
|
|
||||||
$size = max(strlen($abook['url']),40);
|
|
||||||
$input = new html_inputfield(array('name' => $abookid.'_cd_url', 'type' => 'text', 'autocomplete' => 'off', 'value' => $abook['url'], 'size' => $size));
|
|
||||||
$content_url = $input->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// input box for refresh time
|
|
||||||
if (self::no_override('refresh_time', $abook, $prefs)) {
|
|
||||||
$content_refresh_time = $abook['refresh_time'];
|
|
||||||
} else {
|
|
||||||
$input = new html_inputfield(array('name' => $abookid.'_cd_refresh_time', 'type' => 'text', 'autocomplete' => 'off', 'value' => $abook['refresh_time'], 'size' => 10));
|
|
||||||
$content_refresh_time = $input->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::no_override('name', $abook, $prefs)) {
|
|
||||||
$content_name = $abook['name'];
|
|
||||||
} else {
|
|
||||||
$input = new html_inputfield(array('name' => $abookid.'_cd_name', 'type' => 'text', 'autocomplete' => 'off', 'value' => $abook['name'], 'size' => 40));
|
|
||||||
$content_name = $input->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
$retval = array(
|
|
||||||
'options' => array(
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_name')), 'content' => $content_name),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_active')), 'content' => $content_active),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_use_categories')), 'content' => $content_use_categories),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_username')), 'content' => $content_username),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_password')), 'content' => $content_password),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_url')), 'content' => $content_url),
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_refresh_time')), 'content' => $content_refresh_time),
|
|
||||||
),
|
|
||||||
'name' => $blockheader
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$abook['presetname'] && preg_match('/^\d+$/',$abookid)) {
|
|
||||||
$checkbox = new html_checkbox(array('name' => $abookid.'_cd_delete', 'value' => 1));
|
|
||||||
$content_delete = $checkbox->show(0);
|
|
||||||
$retval['options'][] = array('title'=> self::$helper->Q($this->gettext('cd_delete')), 'content' => $content_delete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $retval;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// user preferences
|
|
||||||
function cd_preferences($args)
|
|
||||||
{{{
|
|
||||||
if($args['section'] != 'cd_preferences')
|
|
||||||
return;
|
|
||||||
|
|
||||||
$this->include_stylesheet($this->local_skin_path().'/carddav.css');
|
|
||||||
$this->add_texts('localization/', false);
|
|
||||||
$prefs = carddav_common::get_adminsettings();
|
|
||||||
|
|
||||||
if (!$prefs['_GLOBAL']['suppress_version_warning']){
|
|
||||||
if (version_compare(PHP_VERSION, '5.6.18', '<')) {
|
|
||||||
$args['blocks']['cd_preferences'] = array(
|
|
||||||
'options' => array(
|
|
||||||
array('title'=> self::$helper->Q($this->gettext('cd_php_too_old')), 'content' => PHP_VERSION)
|
|
||||||
),
|
|
||||||
'name' => self::$helper->Q($this->gettext('cd_title'))
|
|
||||||
);
|
|
||||||
return $args;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$abooks = carddav_backend::get_dbrecord($_SESSION['user_id'],'*','addressbooks',false,'user_id');
|
|
||||||
foreach($abooks as $abook) {
|
|
||||||
$presetname = $abook['presetname'];
|
|
||||||
if (empty($presetname) ||
|
|
||||||
(!isset($prefs[$presetname]['hide']) || (isset($prefs[$presetname]['hide']) && $prefs[$presetname]['hide'] === FALSE))) {
|
|
||||||
$abookid = $abook['id'];
|
|
||||||
$blockhdr = $abook['name'];
|
|
||||||
if($abook['presetname'])
|
|
||||||
$blockhdr .= str_replace("_PRESETNAME_", $abook['presetname'], self::$helper->Q($this->gettext('cd_frompreset')));
|
|
||||||
$args['blocks']['cd_preferences'.$abookid] = $this->cd_preferences_buildblock($blockhdr,$abook,$prefs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!array_key_exists('_GLOBAL', $prefs) || !$prefs['_GLOBAL']['fixed']) {
|
|
||||||
$args['blocks']['cd_preferences_section_new'] = $this->cd_preferences_buildblock(
|
|
||||||
self::$helper->Q($this->gettext('cd_newabboxtitle')),
|
|
||||||
array(
|
|
||||||
'id' => 'new',
|
|
||||||
'active' => 1,
|
|
||||||
'use_categories' => 1,
|
|
||||||
'username' => '',
|
|
||||||
'url' => '',
|
|
||||||
'name' => '',
|
|
||||||
'refresh_time' => 1,
|
|
||||||
'presetname' => '',
|
|
||||||
), $prefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return($args);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// add a section to the preferences tab
|
|
||||||
function cd_preferences_section($args)
|
|
||||||
{{{
|
|
||||||
$prefs = carddav_common::get_adminsettings();
|
|
||||||
if (!isset($prefs['_GLOBAL']['hide_preferences']) || (isset($prefs['_GLOBAL']['hide_preferences']) && $prefs['_GLOBAL']['hide_preferences'] === FALSE)) {
|
|
||||||
$this->add_texts('localization/', false);
|
|
||||||
$args['list']['cd_preferences'] = array(
|
|
||||||
'id' => 'cd_preferences',
|
|
||||||
'section' => self::$helper->Q($this->gettext('cd_title'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return($args);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// save preferences
|
|
||||||
function cd_save($args)
|
|
||||||
{{{
|
|
||||||
$this->add_texts('localization/', false);
|
|
||||||
if($args['section'] != 'cd_preferences')
|
|
||||||
return;
|
|
||||||
$prefs = carddav_common::get_adminsettings();
|
|
||||||
if (isset($prefs['_GLOBAL']['hide_preferences']) && $prefs['_GLOBAL']['hide_preferences'] === TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update existing in DB
|
|
||||||
$abooks = carddav_backend::get_dbrecord($_SESSION['user_id'],'id,presetname',
|
|
||||||
'addressbooks', false, 'user_id');
|
|
||||||
|
|
||||||
foreach($abooks as $abook) {
|
|
||||||
$abookid = $abook['id'];
|
|
||||||
if( isset($_POST[$abookid."_cd_delete"]) ) {
|
|
||||||
self::delete_abook($abookid);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$newset = array (
|
|
||||||
'name' => rcube_utils::get_input_value($abookid."_cd_name", rcube_utils::INPUT_POST),
|
|
||||||
'username' => rcube_utils::get_input_value($abookid."_cd_username", rcube_utils::INPUT_POST, true),
|
|
||||||
'url' => rcube_utils::get_input_value($abookid."_cd_url", rcube_utils::INPUT_POST),
|
|
||||||
'active' => isset($_POST[$abookid.'_cd_active']) ? 1 : 0,
|
|
||||||
'use_categories' => isset($_POST[$abookid.'_cd_use_categories']) ? 1 : 0,
|
|
||||||
'refresh_time' => rcube_utils::get_input_value($abookid."_cd_refresh_time", rcube_utils::INPUT_POST),
|
|
||||||
);
|
|
||||||
|
|
||||||
// only set the password if the user entered a new one
|
|
||||||
$password = rcube_utils::get_input_value($abookid."_cd_password", rcube_utils::INPUT_POST, true);
|
|
||||||
if(strlen($password) > 0) {
|
|
||||||
$newset['password'] = $password;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove admin only settings
|
|
||||||
foreach($newset as $pref => $value) {
|
|
||||||
if(self::no_override($pref, $abook, $prefs)) {
|
|
||||||
unset($newset[$pref]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self::update_abook($abookid, $newset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a new address book?
|
|
||||||
$new = rcube_utils::get_input_value('new_cd_name', rcube_utils::INPUT_POST);
|
|
||||||
if ( (!array_key_exists('_GLOBAL', $prefs) || !$prefs['_GLOBAL']['fixed']) && strlen($new) > 0) {
|
|
||||||
$srv = rcube_utils::get_input_value('new_cd_url', rcube_utils::INPUT_POST);
|
|
||||||
$usr = rcube_utils::get_input_value('new_cd_username', rcube_utils::INPUT_POST, true);
|
|
||||||
$pass = rcube_utils::get_input_value('new_cd_password', rcube_utils::INPUT_POST, true);
|
|
||||||
$pass = self::$helper->encrypt_password($pass);
|
|
||||||
$abname = rcube_utils::get_input_value('new_cd_name', rcube_utils::INPUT_POST);
|
|
||||||
$use_categories = intval(rcube_utils::get_input_value('new_cd_use_categories', rcube_utils::INPUT_POST, true), 0);
|
|
||||||
|
|
||||||
$discovery = new carddav_discovery();
|
|
||||||
$srvs = $discovery->find_addressbooks($srv, $usr, $pass);
|
|
||||||
|
|
||||||
if(is_array($srvs) && count($srvs)>0) {
|
|
||||||
foreach($srvs as $srv){
|
|
||||||
self::$helper->debug("ADDING ABOOK " . print_r($srv,true));
|
|
||||||
$this_abname = $abname;
|
|
||||||
if($srv['name']) {
|
|
||||||
$this_abname .= ' (' . $srv['name'] . ')';
|
|
||||||
}
|
|
||||||
self::insert_abook(array(
|
|
||||||
'name' => $this_abname,
|
|
||||||
'username' => $usr,
|
|
||||||
'password' => $pass,
|
|
||||||
'use_categories' => $use_categories,
|
|
||||||
'url' => $srv['href'],
|
|
||||||
'refresh_time' => rcube_utils::get_input_value('new_cd_refresh_time', rcube_utils::INPUT_POST)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$args['abort'] = true;
|
|
||||||
$args['message'] = $abname . ': ' . $this->gettext('cd_err_noabfound');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return($args);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
private static function delete_abook($abookid)
|
|
||||||
{{{
|
|
||||||
carddav_backend::delete_dbrecord($abookid,'addressbooks');
|
|
||||||
// we explicitly delete all data belonging to the addressbook, since
|
|
||||||
// cascaded deleted are not supported by all database backends
|
|
||||||
// ...contacts
|
|
||||||
carddav_backend::delete_dbrecord($abookid,'contacts','abook_id');
|
|
||||||
// ...custom subtypes
|
|
||||||
carddav_backend::delete_dbrecord($abookid,'xsubtypes','abook_id');
|
|
||||||
// ...groups and memberships
|
|
||||||
$delgroups = carddav_backend::get_dbrecord($abookid, 'id as group_id', 'groups', false, 'abook_id');
|
|
||||||
carddav_backend::delete_dbrecord($abookid,'groups','abook_id');
|
|
||||||
carddav_backend::delete_dbrecord($delgroups,'group_user','group_id');
|
|
||||||
}}}
|
|
||||||
|
|
||||||
private static function insert_abook($pa)
|
|
||||||
{{{
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
|
|
||||||
// check parameters
|
|
||||||
if(array_key_exists('refresh_time', $pa)) {
|
|
||||||
$pa['refresh_time'] = self::process_cd_time($pa['refresh_time']);
|
|
||||||
}
|
|
||||||
/* Ensure field lengths */
|
|
||||||
if (array_key_exists('name', $pa)) {
|
|
||||||
if (strlen($pa['name']) > 64){
|
|
||||||
$pa['name'] = substr($pa['name'], 0, 64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array_key_exists('username', $pa)) {
|
|
||||||
if (strlen($pa['username']) > 255){
|
|
||||||
$pa['username'] = substr($pa['username'], 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array_key_exists('presetname', $pa)) {
|
|
||||||
if (strlen($pa['presetname']) > 255){
|
|
||||||
$pa['presetname'] = substr($pa['presetname'], 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$pa['user_id'] = $_SESSION['user_id'];
|
|
||||||
|
|
||||||
// required fields
|
|
||||||
$qf=array('name','username','password','url','user_id');
|
|
||||||
$qv=array();
|
|
||||||
foreach($qf as $f) {
|
|
||||||
if(!array_key_exists($f,$pa)) return false;
|
|
||||||
$qv[] = $pa[$f];
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional fields
|
|
||||||
$qfo = array('active','presetname','use_categories','refresh_time');
|
|
||||||
foreach($qfo as $f) {
|
|
||||||
if(array_key_exists($f,$pa)) {
|
|
||||||
$qf[] = $f;
|
|
||||||
$qv[] = $pa[$f];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$dbh->query('INSERT INTO ' . $dbh->table_name('carddav_addressbooks') .
|
|
||||||
'('. implode(',',$qf) .') ' .
|
|
||||||
'VALUES (?'. str_repeat(',?', count($qf)-1) . ')',
|
|
||||||
$qv
|
|
||||||
);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public static function update_abook($abookid, $pa)
|
|
||||||
{{{
|
|
||||||
$dbh = rcmail::get_instance()->db;
|
|
||||||
|
|
||||||
// check parameters
|
|
||||||
if(array_key_exists('refresh_time', $pa))
|
|
||||||
$pa['refresh_time'] = self::process_cd_time($pa['refresh_time']);
|
|
||||||
|
|
||||||
// encrypt the password before storing it
|
|
||||||
if(array_key_exists('password', $pa))
|
|
||||||
$pa['password'] = self::$helper->encrypt_password($pa['password']);
|
|
||||||
|
|
||||||
/* Ensure field lengths */
|
|
||||||
if (array_key_exists('name', $pa)) {
|
|
||||||
if (strlen($pa['name']) > 64){
|
|
||||||
$pa['name'] = substr($pa['name'], 0, 64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array_key_exists('username', $pa)) {
|
|
||||||
if (strlen($pa['username']) > 255){
|
|
||||||
$pa['username'] = substr($pa['username'], 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array_key_exists('presetname', $pa)) {
|
|
||||||
if (strlen($pa['presetname']) > 255){
|
|
||||||
$pa['presetname'] = substr($pa['presetname'], 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional fields
|
|
||||||
$qfo=array('name','username','password','url','active','refresh_time','sync_token');
|
|
||||||
$qf=array();
|
|
||||||
$qv=array();
|
|
||||||
|
|
||||||
foreach($qfo as $f) {
|
|
||||||
if(array_key_exists($f,$pa)) {
|
|
||||||
$qf[] = $f;
|
|
||||||
$qv[] = $pa[$f];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(count($qf) <= 0) return true;
|
|
||||||
|
|
||||||
$qv[] = $abookid;
|
|
||||||
$dbh->query('UPDATE ' .
|
|
||||||
$dbh->table_name('carddav_addressbooks') .
|
|
||||||
' SET ' . implode('=?,', $qf) . '=?' .
|
|
||||||
' WHERE id=?',
|
|
||||||
$qv
|
|
||||||
);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
File diff suppressed because it is too large
Load Diff
@ -1,397 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
RCM CardDAV Plugin
|
|
||||||
Copyright (C) 2011-2016 Benjamin Schieder <rcmcarddav@wegwerf.anderdonau.de>,
|
|
||||||
Michael Stilkerich <ms@mike2k.de>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (file_exists(__DIR__ . '/vendor/autoload.php'))
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
|
||||||
|
|
||||||
\Httpful\Bootstrap::init();
|
|
||||||
|
|
||||||
class carddav_common
|
|
||||||
{
|
|
||||||
const DEBUG = false; // set to true for basic debugging
|
|
||||||
const DEBUG_HTTP = false; // set to true for debugging raw http stream
|
|
||||||
|
|
||||||
const NSDAV = 'DAV:';
|
|
||||||
const NSCARDDAV = 'urn:ietf:params:xml:ns:carddav';
|
|
||||||
|
|
||||||
// admin settings from config.inc.php
|
|
||||||
private static $admin_settings;
|
|
||||||
// encryption scheme
|
|
||||||
public static $pwstore_scheme = 'base64';
|
|
||||||
|
|
||||||
private $module_prefix = '';
|
|
||||||
|
|
||||||
public function __construct($module_prefix = '')
|
|
||||||
{{{
|
|
||||||
$this->module_prefix = $module_prefix;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public static function concaturl($str, $cat)
|
|
||||||
{{{
|
|
||||||
preg_match(";(^https?://[^/]+)(.*);", $str, $match);
|
|
||||||
$hostpart = $match[1];
|
|
||||||
$urlpart = $match[2];
|
|
||||||
|
|
||||||
// is $cat already a full URL?
|
|
||||||
if(strpos($cat, '://') !== FALSE) {
|
|
||||||
return $cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is $cat a simple filename?
|
|
||||||
// then attach it to the URL
|
|
||||||
if (substr($cat, 0, 1) != "/"){
|
|
||||||
$urlpart .= "/$cat";
|
|
||||||
|
|
||||||
// $cat is a full path, the append it to the
|
|
||||||
// hostpart only
|
|
||||||
} else {
|
|
||||||
$urlpart = $cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove // in the path
|
|
||||||
$urlpart = preg_replace(';//+;','/',$urlpart);
|
|
||||||
return $hostpart.$urlpart;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// log helpers
|
|
||||||
private function getCaller()
|
|
||||||
{{{
|
|
||||||
// determine calling function for debug output
|
|
||||||
if (version_compare(PHP_VERSION, "5.4", ">=")){
|
|
||||||
$caller=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,3);
|
|
||||||
} else {
|
|
||||||
$caller=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
|
||||||
}
|
|
||||||
$caller=$caller[2]['function'];
|
|
||||||
return $caller;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function warn()
|
|
||||||
{{{
|
|
||||||
$caller=self::getCaller();
|
|
||||||
rcmail::write_log("carddav.warn", $this->module_prefix . "($caller) " . implode(' ', func_get_args()));
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function debug()
|
|
||||||
{{{
|
|
||||||
if(self::DEBUG) {
|
|
||||||
$caller=self::getCaller();
|
|
||||||
rcmail::write_log("carddav", $this->module_prefix . "($caller) " . implode(' ', func_get_args()));
|
|
||||||
}
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function debug_http()
|
|
||||||
{{{
|
|
||||||
if(self::DEBUG_HTTP) {
|
|
||||||
$caller=self::getCaller();
|
|
||||||
rcmail::write_log("carddav", $this->module_prefix . "($caller) " . implode(' ', func_get_args()));
|
|
||||||
}
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// XML helpers
|
|
||||||
public function checkAndParseXML($reply) {
|
|
||||||
if(!is_array($reply))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(!self::check_contenttype($reply['headers']['content-type'], ';(text|application)/xml;'))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
$xml = new SimpleXMLElement($reply['body']);
|
|
||||||
$this->registerNamespaces($xml);
|
|
||||||
return $xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerNamespaces($xml) {
|
|
||||||
// Use slightly complex prefixes to avoid conflicts
|
|
||||||
$xml->registerXPathNamespace('RCMCC', self::NSCARDDAV);
|
|
||||||
$xml->registerXPathNamespace('RCMCD', self::NSDAV);
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP helpers
|
|
||||||
/**
|
|
||||||
* @param $url: url of the requested resource
|
|
||||||
*
|
|
||||||
* @param $http_opts: Options for the HTTP request, keys:
|
|
||||||
* - method: request method (GET, PROPFIND, etc.)
|
|
||||||
* - content: request body
|
|
||||||
* - header: array of HTTP request headers as simple strings
|
|
||||||
*
|
|
||||||
* @param $carddav: config array containing at least the keys
|
|
||||||
* - url: base url, used if $url is a relative url
|
|
||||||
* - username
|
|
||||||
* - password: password (encoded/encrypted form as stored in DB)
|
|
||||||
*/
|
|
||||||
public function cdfopen($url, $http_opts, $carddav)
|
|
||||||
{{{
|
|
||||||
$redirect_limit = 5;
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
|
|
||||||
$username=$carddav['username'];
|
|
||||||
$password = self::decrypt_password($carddav['password']);
|
|
||||||
$baseurl=$carddav['url'];
|
|
||||||
|
|
||||||
// determine calling function for debug output
|
|
||||||
$caller=self::getCaller();
|
|
||||||
|
|
||||||
$local = $rcmail->user->get_username('local');
|
|
||||||
$domain = $rcmail->user->get_username('domain');
|
|
||||||
|
|
||||||
// Substitute Placeholders
|
|
||||||
$username = str_replace( '%u', $_SESSION['username'], $username);
|
|
||||||
$username = str_replace( '%V' ,str_replace('@','_', str_replace('.','_',$_SESSION['username'])), $username);
|
|
||||||
$username = str_replace( '%l', $local, $username);
|
|
||||||
$username = str_replace( '%d', $domain, $username);
|
|
||||||
if($password == '%p')
|
|
||||||
$password = $rcmail->decrypt($_SESSION['password']);
|
|
||||||
$baseurl = str_replace("%u", $username, $carddav['url']);
|
|
||||||
$url = str_replace("%u", $username, $url);
|
|
||||||
$baseurl = str_replace("%l", $local, $baseurl);
|
|
||||||
$url = str_replace("%l", $local, $url);
|
|
||||||
$baseurl = str_replace("%d", $domain, $baseurl);
|
|
||||||
$url = str_replace("%d", $domain, $url);
|
|
||||||
|
|
||||||
// if $url is relative, prepend the base url
|
|
||||||
$url = self::concaturl($baseurl, $url);
|
|
||||||
|
|
||||||
do {
|
|
||||||
$isRedirect = false;
|
|
||||||
if (self::DEBUG){ $this->debug("$caller requesting $url as user $username [RL $redirect_limit]"); }
|
|
||||||
|
|
||||||
$httpful = \Httpful\Request::init();
|
|
||||||
$scheme = strtolower($carddav['authentication_scheme']);
|
|
||||||
if ($scheme != "basic" && $scheme != "digest" && $scheme != "negotiate"){
|
|
||||||
/* figure out authentication */
|
|
||||||
$httpful->addHeader("User-Agent", "RCM CardDAV plugin/3.0.3");
|
|
||||||
$httpful->uri($url);
|
|
||||||
$httpful->method($http_opts['method']);
|
|
||||||
$error = $httpful->send();
|
|
||||||
|
|
||||||
$httpful = \Httpful\Request::init();
|
|
||||||
$scheme = "unknown";
|
|
||||||
// Using raw_headers since there might be multiple www-authenticate headers
|
|
||||||
if (preg_match("/^(.*\n)*WWW-Authenticate:\s+Negotiate\b/i", $error->raw_headers) && !empty($_SERVER['KRB5CCNAME'])){
|
|
||||||
$httpful->negotiateAuth($username, $password);
|
|
||||||
$scheme = "negotiate";
|
|
||||||
} else if (preg_match("/\bDigest\b/i", $error->headers["www-authenticate"])){
|
|
||||||
$httpful->digestAuth($username, $password);
|
|
||||||
$scheme = "digest";
|
|
||||||
} else if (preg_match("/\bBasic\b/i", $error->headers["www-authenticate"])){
|
|
||||||
$httpful->basicAuth($username, $password);
|
|
||||||
$scheme = "basic";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scheme != "unknown")
|
|
||||||
carddav_backend::update_addressbook($carddav['abookid'], array("authentication_scheme"), array($scheme));
|
|
||||||
} else {
|
|
||||||
// if we have KRB5CCNAME, use negotiate even if current scheme is basic
|
|
||||||
if ((strtolower($scheme) == "negotiate" || strtolower($scheme) == "basic") && !empty($_SERVER['KRB5CCNAME'])) {
|
|
||||||
$httpful->negotiateAuth($username, $password);
|
|
||||||
} else if (strtolower($scheme) == "digest"){
|
|
||||||
$httpful->digestAuth($username, $password);
|
|
||||||
// if we don't have KRB5CCNAME, use basic even if current scheme is negotiate
|
|
||||||
} else if (strtolower($scheme) == "negotiate" || strtolower($scheme) == "basic"){
|
|
||||||
$httpful->basicAuth($username, $password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$httpful->addHeader("User-Agent", "RCM CardDAV plugin/3.0.3");
|
|
||||||
$httpful->uri($url);
|
|
||||||
|
|
||||||
$httpful->method($http_opts['method']);
|
|
||||||
if (array_key_exists('content',$http_opts) && strlen($http_opts['content'])>0 && $http_opts['method'] != "GET"){
|
|
||||||
$httpful->body($http_opts['content']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(array_key_exists('header',$http_opts)) {
|
|
||||||
foreach ($http_opts['header'] as $header){
|
|
||||||
$h = explode(": ", $header);
|
|
||||||
if (strlen($h[0]) > 0 && strlen($h[1]) > 0){
|
|
||||||
// Only append headers with key AND value
|
|
||||||
$httpful->addHeader($h[0], $h[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$reply = $httpful->send();
|
|
||||||
$scode = $reply->code;
|
|
||||||
if (self::DEBUG){ $this->debug("Code: $scode"); }
|
|
||||||
|
|
||||||
$isRedirect = ($scode>300 && $scode<304) || $scode==307;
|
|
||||||
if($isRedirect && strlen($reply->headers['location'])>0) {
|
|
||||||
$url = self::concaturl($baseurl, $reply->headers['location']);
|
|
||||||
} else {
|
|
||||||
$retVal["status"] = $scode;
|
|
||||||
$retVal["headers"] = $reply->headers;
|
|
||||||
$retVal["body"] = $reply->raw_body;
|
|
||||||
if (self::DEBUG_HTTP){ $this->debug_http("success: ".var_export($retVal, true)); }
|
|
||||||
return $retVal;
|
|
||||||
}
|
|
||||||
} while($redirect_limit-->0 && $isRedirect);
|
|
||||||
|
|
||||||
return $reply->code;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function check_contenttype($ctheader, $expectedct)
|
|
||||||
{{{
|
|
||||||
if(!is_array($ctheader)) {
|
|
||||||
$ctheader = array($ctheader);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($ctheader as $ct) {
|
|
||||||
if(preg_match($expectedct, $ct))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// password helpers
|
|
||||||
private function carddav_des_key()
|
|
||||||
{{{
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
$imap_password = $rcmail->decrypt($_SESSION['password']);
|
|
||||||
while(strlen($imap_password)<24) {
|
|
||||||
$imap_password .= $imap_password;
|
|
||||||
}
|
|
||||||
return substr($imap_password, 0, 24);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function encrypt_password($clear)
|
|
||||||
{{{
|
|
||||||
if(strcasecmp(self::$pwstore_scheme, 'plain')===0)
|
|
||||||
return $clear;
|
|
||||||
|
|
||||||
if(strcasecmp(self::$pwstore_scheme, 'encrypted')===0) {
|
|
||||||
|
|
||||||
// return {IGNORE} scheme if session password is empty (krb_authentication plugin)
|
|
||||||
if(empty($_SESSION['password'])) return '{IGNORE}';
|
|
||||||
|
|
||||||
// encrypted with IMAP password
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
|
|
||||||
$imap_password = self::carddav_des_key();
|
|
||||||
$deskey_backup = $rcmail->config->set('carddav_des_key', $imap_password);
|
|
||||||
|
|
||||||
$crypted = $rcmail->encrypt($clear, 'carddav_des_key');
|
|
||||||
|
|
||||||
// there seems to be no way to unset a preference
|
|
||||||
$deskey_backup = $rcmail->config->set('carddav_des_key', '');
|
|
||||||
|
|
||||||
return '{ENCRYPTED}'.$crypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strcasecmp(self::$pwstore_scheme, 'des_key')===0) {
|
|
||||||
|
|
||||||
// encrypted with global des_key
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
$crypted = $rcmail->encrypt($clear);
|
|
||||||
|
|
||||||
return '{DES_KEY}'.$crypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// default: base64-coded password
|
|
||||||
return '{BASE64}'.base64_encode($clear);
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function password_scheme($crypt)
|
|
||||||
{{{
|
|
||||||
if(strpos($crypt, '{IGNORE}') === 0)
|
|
||||||
return 'ignore';
|
|
||||||
|
|
||||||
if(strpos($crypt, '{ENCRYPTED}') === 0)
|
|
||||||
return 'encrypted';
|
|
||||||
|
|
||||||
if(strpos($crypt, '{DES_KEY}') === 0)
|
|
||||||
return 'des_key';
|
|
||||||
|
|
||||||
if(strpos($crypt, '{BASE64}') === 0)
|
|
||||||
return 'base64';
|
|
||||||
|
|
||||||
// unknown scheme, assume cleartext
|
|
||||||
return 'plain';
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public function decrypt_password($crypt)
|
|
||||||
{{{
|
|
||||||
if(strpos($crypt, '{ENCRYPTED}') === 0) {
|
|
||||||
// return {IGNORE} scheme if session password is empty (krb_authentication plugin)
|
|
||||||
if (empty($_SESSION['password'])) return '{IGNORE}';
|
|
||||||
|
|
||||||
$crypt = substr($crypt, strlen('{ENCRYPTED}'));
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
|
|
||||||
$imap_password = self::carddav_des_key();
|
|
||||||
$deskey_backup = $rcmail->config->set('carddav_des_key', $imap_password);
|
|
||||||
|
|
||||||
$clear = $rcmail->decrypt($crypt, 'carddav_des_key');
|
|
||||||
|
|
||||||
// there seems to be no way to unset a preference
|
|
||||||
$deskey_backup = $rcmail->config->set('carddav_des_key', '');
|
|
||||||
|
|
||||||
return $clear;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strpos($crypt, '{DES_KEY}') === 0) {
|
|
||||||
$crypt = substr($crypt, strlen('{DES_KEY}'));
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
|
|
||||||
return $rcmail->decrypt($crypt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strpos($crypt, '{BASE64}') === 0) {
|
|
||||||
$crypt = substr($crypt, strlen('{BASE64}'));
|
|
||||||
return base64_decode($crypt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// unknown scheme, assume cleartext
|
|
||||||
return $crypt;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// admin settings from config.inc.php
|
|
||||||
public static function get_adminsettings()
|
|
||||||
{{{
|
|
||||||
if(is_array(self::$admin_settings))
|
|
||||||
return self::$admin_settings;
|
|
||||||
|
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
$prefs = array();
|
|
||||||
$configfile = dirname(__FILE__)."/config.inc.php";
|
|
||||||
if (file_exists($configfile)){
|
|
||||||
require("$configfile");
|
|
||||||
}
|
|
||||||
self::$admin_settings = $prefs;
|
|
||||||
|
|
||||||
if(is_array($prefs['_GLOBAL'])) {
|
|
||||||
$scheme = $prefs['_GLOBAL']['pwstore_scheme'];
|
|
||||||
if(preg_match("/^(plain|base64|encrypted|des_key)$/", $scheme))
|
|
||||||
self::$pwstore_scheme = $scheme;
|
|
||||||
}
|
|
||||||
return $prefs;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// short form for deprecated Q helper function
|
|
||||||
public function Q($str, $mode='strict', $newlines=true)
|
|
||||||
{{{
|
|
||||||
return rcube_utils::rep_specialchars_output($str, 'html', $mode, $newlines);
|
|
||||||
}}}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -1,280 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
RCM CardDAV Plugin
|
|
||||||
Copyright (C) 2011-2016 Benjamin Schieder <rcmcarddav@wegwerf.anderdonau.de>,
|
|
||||||
Michael Stilkerich <ms@mike2k.de>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
require_once("carddav_backend.php");
|
|
||||||
require_once("carddav_common.php");
|
|
||||||
|
|
||||||
class carddav_discovery
|
|
||||||
{
|
|
||||||
private static $helper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines the location of the addressbook for the current user on the
|
|
||||||
* CardDAV server.
|
|
||||||
*
|
|
||||||
* Returns: Array of found addressbook. Each array element is array with keys:
|
|
||||||
* - name: Name of the addressbook reported by server
|
|
||||||
* - href: URL to the addressbook collection
|
|
||||||
*
|
|
||||||
* On error, false is returned.
|
|
||||||
*/
|
|
||||||
public function find_addressbooks($url, $user, $password)
|
|
||||||
{{{
|
|
||||||
if (!preg_match(';^(([^:]+)://)?(([^/:]+)(:([0-9]+))?)(/?.*)$;', $url, $match))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
$protocol = $match[2]; // optional
|
|
||||||
$host = $match[4]; // mandatory
|
|
||||||
$port = $match[6]; // optional
|
|
||||||
$path = $match[7]; // optional
|
|
||||||
|
|
||||||
// plain is only used if http was explicitly given
|
|
||||||
$use_ssl = !($protocol == "http");
|
|
||||||
|
|
||||||
// setup default values if no user values given
|
|
||||||
if($use_ssl) {
|
|
||||||
$protocol = $protocol?$protocol:'https';
|
|
||||||
$port = $port ?$port :443;
|
|
||||||
} else {
|
|
||||||
$protocol = $protocol?$protocol:'http';
|
|
||||||
$port = $port ?$port :80;
|
|
||||||
}
|
|
||||||
|
|
||||||
$services = $this->find_servers($host, $use_ssl);
|
|
||||||
|
|
||||||
// Fallback: If no DNS provided, we use the data given by the user/defaults
|
|
||||||
if(count($services) == 0) {
|
|
||||||
$services[] = array(
|
|
||||||
'host' => $host,
|
|
||||||
'port' => ($port ? $port : ($use_ssl ? 443 : 80)),
|
|
||||||
'baseurl' => "$protocol://$host:$port",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$services = $this->find_baseurls($services);
|
|
||||||
|
|
||||||
// if the user specified a full URL, we try that first
|
|
||||||
if(strlen($path) > 2) {
|
|
||||||
$userspecified = array(
|
|
||||||
'host' => $host,
|
|
||||||
'port' => ($port ? $port : ($use_ssl ? 443 : 80)),
|
|
||||||
'baseurl' => "$protocol://$host:$port",
|
|
||||||
'paths' => array($path),
|
|
||||||
);
|
|
||||||
array_unshift($services, $userspecified);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cdfopen_cfg = array('username'=>$user, 'password'=>$password);
|
|
||||||
|
|
||||||
// now check each of them until we find something (or don't)
|
|
||||||
foreach($services as $service) {
|
|
||||||
$cdfopen_cfg['url'] = $service['baseurl'];
|
|
||||||
|
|
||||||
foreach($service['paths'] as $path) {
|
|
||||||
$aBooks = $this->retrieve_addressbooks($path, $cdfopen_cfg);
|
|
||||||
if(is_array($aBooks) && count($aBooks)>0)
|
|
||||||
return $aBooks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
private function retrieve_addressbooks($path, $cdfopen_cfg, $recurse=false)
|
|
||||||
{{{
|
|
||||||
$baseurl = $cdfopen_cfg['url'];
|
|
||||||
$url = carddav_common::concaturl($baseurl, $path);
|
|
||||||
$depth = ($recurse ? 1 : 0);
|
|
||||||
self::$helper->debug("SEARCHING $url (Depth: ".$depth.")");
|
|
||||||
|
|
||||||
// check if the given URL points to an addressbook
|
|
||||||
$opts = array(
|
|
||||||
'method'=>"PROPFIND",
|
|
||||||
'header'=>array("Depth: " . $depth, 'Content-Type: application/xml; charset="utf-8"'),
|
|
||||||
'content'=> <<<EOF
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"><D:prop>
|
|
||||||
<D:current-user-principal/>
|
|
||||||
<D:resourcetype />
|
|
||||||
<D:displayname />
|
|
||||||
<C:addressbook-home-set/>
|
|
||||||
</D:prop></D:propfind>
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
|
|
||||||
$reply = self::$helper->cdfopen($url, $opts, $cdfopen_cfg);
|
|
||||||
$xml = self::$helper->checkAndParseXML($reply);
|
|
||||||
if($xml === false) return false;
|
|
||||||
|
|
||||||
$aBooks = array();
|
|
||||||
|
|
||||||
// Check if we found addressbooks at the URL
|
|
||||||
$xpresult = $xml->xpath('//RCMCD:response[descendant::RCMCD:resourcetype/RCMCC:addressbook]');
|
|
||||||
foreach($xpresult as $ab) {
|
|
||||||
self::$helper->registerNamespaces($ab);
|
|
||||||
$aBook = array();
|
|
||||||
list($aBook['href']) = $ab->xpath('child::RCMCD:href');
|
|
||||||
list($aBook['name']) = $ab->xpath('descendant::RCMCD:displayname');
|
|
||||||
$aBook['href'] = (string) $aBook['href'];
|
|
||||||
$aBook['name'] = (string) $aBook['name'];
|
|
||||||
|
|
||||||
if(strlen($aBook['href']) > 0) {
|
|
||||||
$aBook['href'] = carddav_common::concaturl($baseurl, $aBook['href']);
|
|
||||||
self::$helper->debug("found abook: ".$aBook['name']." at ".$aBook['href']);
|
|
||||||
$aBooks[] = $aBook;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// found -> done
|
|
||||||
if(count($aBooks) > 0) return $aBooks;
|
|
||||||
|
|
||||||
if ($recurse === false) {
|
|
||||||
// Check some additional URLs:
|
|
||||||
$additional_urls = array();
|
|
||||||
|
|
||||||
// (1) original URL
|
|
||||||
$additional_urls[] = $url;
|
|
||||||
|
|
||||||
// (2) see if the server told us the addressbook home location
|
|
||||||
$abookhome = $xml->xpath('//RCMCC:addressbook-home-set/RCMCD:href');
|
|
||||||
if (count($abookhome) != 0) {
|
|
||||||
self::$helper->debug("addressbook home: ".$abookhome[0]);
|
|
||||||
$additional_urls[] = $abookhome[0];
|
|
||||||
}
|
|
||||||
// (3) see if we got a principal URL
|
|
||||||
$princurl = $xml->xpath('//RCMCD:current-user-principal/RCMCD:href');
|
|
||||||
if (count($princurl) != 0) {
|
|
||||||
self::$helper->debug("principal URL: ".$princurl[0]);
|
|
||||||
$additional_urls[] = $princurl[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($additional_urls as $other_url) {
|
|
||||||
self::$helper->debug("Searching additional URL: $other_url");
|
|
||||||
if(strlen($other_url) <= 0) continue;
|
|
||||||
|
|
||||||
// if the server returned a full URL, adjust the base url
|
|
||||||
if (preg_match(';^[^/]+://[^/]+;', $other_url, $match)) {
|
|
||||||
$cdfopen_cfg['url'] = $match[0];
|
|
||||||
} else {
|
|
||||||
// restore original baseurl, may have changed in prev URL check
|
|
||||||
$cdfopen_cfg['url'] = $baseurl;
|
|
||||||
}
|
|
||||||
$aBooks = $this->retrieve_addressbooks($other_url, $cdfopen_cfg, $other_url != $princurl[0]);
|
|
||||||
// found -> done
|
|
||||||
if (!($aBooks === false) && count($aBooks) > 0) return $aBooks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// (4) there is no more we can do -> fail
|
|
||||||
self::$helper->debug("no principal URL found");
|
|
||||||
return false;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// get services by querying DNS SRV records
|
|
||||||
private function find_servers($host, $ssl)
|
|
||||||
{{{
|
|
||||||
if($ssl) {
|
|
||||||
$srvpfx = '_carddavs';
|
|
||||||
$defport = 443;
|
|
||||||
$protocol = 'https';
|
|
||||||
} else {
|
|
||||||
$srvpfx = '_carddav';
|
|
||||||
$defport = 80;
|
|
||||||
$protocol = 'http';
|
|
||||||
}
|
|
||||||
|
|
||||||
$srv = "$srvpfx._tcp.$host";
|
|
||||||
|
|
||||||
// query SRV records
|
|
||||||
$dnsresults = dns_get_record($srv, DNS_SRV);
|
|
||||||
|
|
||||||
// order according to priority and weight
|
|
||||||
// TODO weight is not quite correctly handled atm, see RFC2782,
|
|
||||||
// but this is not crucial to functionality
|
|
||||||
$sortPrioWeight = function($a, $b) {
|
|
||||||
if ($a['pri'] != $b['pri']) {
|
|
||||||
return $b['pri'] - $a['pri'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $a['weight'] - $b['weight'];
|
|
||||||
};
|
|
||||||
|
|
||||||
usort($dnsresults, $sortPrioWeight);
|
|
||||||
|
|
||||||
// build results
|
|
||||||
$result = array();
|
|
||||||
foreach($dnsresults as $dnsres) {
|
|
||||||
$target = $dnsres['target'];
|
|
||||||
$port = $dnsres['port'] ? $dnsres['port'] : $defport;
|
|
||||||
$baseurl = "$protocol://$target:$port";
|
|
||||||
if($target) {
|
|
||||||
self::$helper->debug("found service: $baseurl");
|
|
||||||
|
|
||||||
$result[] = array(
|
|
||||||
'host' => $target,
|
|
||||||
'port' => $port,
|
|
||||||
'baseurl' => $baseurl,
|
|
||||||
'dnssrv' => "$srvpfx._tcp.$target",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
// discover path and add default paths to services
|
|
||||||
private function find_baseurls($services)
|
|
||||||
{{{
|
|
||||||
foreach($services as &$service) {
|
|
||||||
$baseurl = $service['baseurl'];
|
|
||||||
$dnssrv = $service['dnssrv'];
|
|
||||||
|
|
||||||
$paths = array();
|
|
||||||
|
|
||||||
$dnsresults = dns_get_record($dnssrv, DNS_TXT);
|
|
||||||
foreach($dnsresults as $dnsresult) {
|
|
||||||
if($dnsresult['host'] != $dnssrv) continue;
|
|
||||||
|
|
||||||
foreach($dnsresult['entries'] as $ent) {
|
|
||||||
if (preg_match('^path=(.+)', $ent, $match))
|
|
||||||
$paths[] = $match[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// as fallback try these default paths
|
|
||||||
$paths[] = '/.well-known/carddav';
|
|
||||||
$paths[] = '/';
|
|
||||||
|
|
||||||
$service['paths'] = $paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $services;
|
|
||||||
}}}
|
|
||||||
|
|
||||||
public static function initClass()
|
|
||||||
{{{
|
|
||||||
self::$helper = new carddav_common('DISCOVERY: ');
|
|
||||||
}}}
|
|
||||||
}
|
|
||||||
|
|
||||||
carddav_discovery::initClass();
|
|
||||||
|
|
||||||
?>
|
|
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "roundcube/carddav",
|
|
||||||
"type": "roundcube-plugin",
|
|
||||||
"description": "CardDAV adapter for connecting to CardDAV-enabled addressbooks",
|
|
||||||
"keywords": ["addressbook","carddav","contacts","owncloud","davical"],
|
|
||||||
"homepage": "https://www.benjamin-schieder.de/carddav.html",
|
|
||||||
"license": "GPL-2.0",
|
|
||||||
"version": "3.0.3",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Benjamin Schieder",
|
|
||||||
"email": "carddav@wegwerf.anderdonau.de",
|
|
||||||
"homepage": "https://www.benjamin.schieder.de/",
|
|
||||||
"role": "Developer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Michael Stilkerich",
|
|
||||||
"email": "michael@stilkerich.eu",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "vcs",
|
|
||||||
"url": "git://github.com/blind-coder/rcmcarddav.git"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": ">=5.6.18",
|
|
||||||
"nategood/httpful": "~0.2",
|
|
||||||
"sabre/vobject": "~3.4"
|
|
||||||
},
|
|
||||||
"extra": {
|
|
||||||
"roundcube": {
|
|
||||||
"min-version": "1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
136
plugins/carddav/composer.lock
generated
136
plugins/carddav/composer.lock
generated
@ -1,136 +0,0 @@
|
|||||||
{
|
|
||||||
"_readme": [
|
|
||||||
"This file locks the dependencies of your project to a known state",
|
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
|
||||||
"This file is @generated automatically"
|
|
||||||
],
|
|
||||||
"content-hash": "c645717601239af47e93d45ac34cb26e",
|
|
||||||
"packages": [
|
|
||||||
{
|
|
||||||
"name": "nategood/httpful",
|
|
||||||
"version": "0.2.20",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/nategood/httpful.git",
|
|
||||||
"reference": "c1cd4d46a4b281229032cf39d4dd852f9887c0f6"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/nategood/httpful/zipball/c1cd4d46a4b281229032cf39d4dd852f9887c0f6",
|
|
||||||
"reference": "c1cd4d46a4b281229032cf39d4dd852f9887c0f6",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-curl": "*",
|
|
||||||
"php": ">=5.3"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "*"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-0": {
|
|
||||||
"Httpful": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nate Good",
|
|
||||||
"email": "me@nategood.com",
|
|
||||||
"homepage": "http://nategood.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "A Readable, Chainable, REST friendly, PHP HTTP Client",
|
|
||||||
"homepage": "http://github.com/nategood/httpful",
|
|
||||||
"keywords": [
|
|
||||||
"api",
|
|
||||||
"curl",
|
|
||||||
"http",
|
|
||||||
"requests",
|
|
||||||
"rest",
|
|
||||||
"restful"
|
|
||||||
],
|
|
||||||
"time": "2015-10-26T16:11:30+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "sabre/vobject",
|
|
||||||
"version": "3.5.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/sabre-io/vobject.git",
|
|
||||||
"reference": "129d80533a9ec0d9cacfb50b51180c34edb6874c"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/129d80533a9ec0d9cacfb50b51180c34edb6874c",
|
|
||||||
"reference": "129d80533a9ec0d9cacfb50b51180c34edb6874c",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"php": ">=5.3.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "*",
|
|
||||||
"squizlabs/php_codesniffer": "*"
|
|
||||||
},
|
|
||||||
"bin": [
|
|
||||||
"bin/vobject",
|
|
||||||
"bin/generate_vcards"
|
|
||||||
],
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "3.2.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Sabre\\VObject\\": "lib/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"BSD-3-Clause"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Evert Pot",
|
|
||||||
"email": "me@evertpot.com",
|
|
||||||
"homepage": "http://evertpot.com/",
|
|
||||||
"role": "Developer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Dominik Tobschall",
|
|
||||||
"email": "dominik@fruux.com",
|
|
||||||
"homepage": "http://tobschall.de/",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
|
|
||||||
"homepage": "http://sabre.io/vobject/",
|
|
||||||
"keywords": [
|
|
||||||
"VObject",
|
|
||||||
"iCalendar",
|
|
||||||
"jCal",
|
|
||||||
"jCard",
|
|
||||||
"vCard"
|
|
||||||
],
|
|
||||||
"time": "2016-10-07T03:20:40+00:00"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"packages-dev": [],
|
|
||||||
"aliases": [],
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"stability-flags": [],
|
|
||||||
"prefer-stable": false,
|
|
||||||
"prefer-lowest": false,
|
|
||||||
"platform": {
|
|
||||||
"php": ">=5.6.18"
|
|
||||||
},
|
|
||||||
"platform-dev": []
|
|
||||||
}
|
|
@ -1,217 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
//// RCMCardDAV Plugin Admin Settings
|
|
||||||
|
|
||||||
//// ** GLOBAL SETTINGS
|
|
||||||
|
|
||||||
// Disallow users to add / edit / delete custom addressbooks (default: false)
|
|
||||||
//
|
|
||||||
// If true, User cannot add custom addressbooks
|
|
||||||
// If false, user can add / edit / delete custom addressbooks
|
|
||||||
//
|
|
||||||
// This option only affects custom addressbooks. Preset addressbooks (see below)
|
|
||||||
// are not affected.
|
|
||||||
// $prefs['_GLOBAL']['fixed'] = true;
|
|
||||||
|
|
||||||
// When enabled, this option hides the 'CardDAV' section inside Preferences.
|
|
||||||
// $prefs['_GLOBAL']['hide_preferences'] = true;
|
|
||||||
|
|
||||||
// Scheme for storing the CardDAV passwords, in order from least to best security.
|
|
||||||
// Options:
|
|
||||||
// plain: store as plaintext
|
|
||||||
// base64: store encoded with base64 (default)
|
|
||||||
// des_key: store encrypted with global des_key of roundcube
|
|
||||||
// encrypted: store encrypted with IMAP password of the user
|
|
||||||
// NOTE: if the IMAP password of the user changes, the stored
|
|
||||||
// CardDAV passwords cannot be decrypted anymore and the user
|
|
||||||
// needs to reenter them.
|
|
||||||
// $prefs['_GLOBAL']['pwstore_scheme'] = 'base64';
|
|
||||||
|
|
||||||
// Allow suppression of the warning that PHP is too old.
|
|
||||||
//
|
|
||||||
// If true, the PHP version is not checked. Use at own risk.
|
|
||||||
// If false, the PHP version is checked and RCMCardDAV will not run if it is
|
|
||||||
// too old.
|
|
||||||
$prefs['_GLOBAL']['suppress_version_warning'] = false;
|
|
||||||
|
|
||||||
// Enable a workaround for broken sync-collection support in the
|
|
||||||
// server. RFC 6578 specifies the "sync-collection" method for
|
|
||||||
// synchronizing collections of things over WebDAV. It is more
|
|
||||||
// efficient -- but also more complicated -- than simply retrieving
|
|
||||||
// the whole collection again as necessary. As a result, some server
|
|
||||||
// implementations are buggy. Specifically DAViCal and Radicale are
|
|
||||||
// known to have problems. If changes (updates, deletions) from one
|
|
||||||
// connection do not sync to another, you can try enabling this
|
|
||||||
// workaround to revert to the inefficient-but-simple method.
|
|
||||||
$prefs['_GLOBAL']['sync_collection_workaround'] = false;
|
|
||||||
|
|
||||||
//// ** ADDRESSBOOK PRESETS
|
|
||||||
|
|
||||||
// Each addressbook preset takes the following form:
|
|
||||||
/*
|
|
||||||
$prefs['<Presetname>'] = array(
|
|
||||||
// required attributes
|
|
||||||
'name' => '<Addressbook Name>',
|
|
||||||
'username' => '<CardDAV Username>',
|
|
||||||
'password' => '<CardDAV Password>',
|
|
||||||
'url' => '<CardDAV URL>',
|
|
||||||
|
|
||||||
// optional attributes
|
|
||||||
'active' => <true or false>,
|
|
||||||
'readonly' => <true or false>,
|
|
||||||
'refresh_time' => '<Refresh Time in Hours, Format HH[:MM[:SS]]>',
|
|
||||||
|
|
||||||
// attributes that are fixed (i.e., not editable by the user) and
|
|
||||||
// auto-updated for this preset
|
|
||||||
'fixed' => array( < 0 or more of the other attribute keys > ),
|
|
||||||
|
|
||||||
// always require these attributes, even for addressbook view
|
|
||||||
'require_always' => ['email'],
|
|
||||||
|
|
||||||
// hide this preset from CalDAV preferences section so users can't even
|
|
||||||
// see it
|
|
||||||
'hide' => <true or false>,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// All values in angle brackets <VALUE> have to be substituted.
|
|
||||||
//
|
|
||||||
// The meaning of the different parameters is as follows:
|
|
||||||
//
|
|
||||||
// <Presetname>: Unique preset name, must not be '_GLOBAL'. The presetname is
|
|
||||||
// not user visible and only used for an internal mapping between
|
|
||||||
// addressbooks created from a preset and the preset itself. You
|
|
||||||
// should never change this throughout its lifetime.
|
|
||||||
//
|
|
||||||
// The following parameters are REQUIRED and need to be specified for any preset.
|
|
||||||
//
|
|
||||||
// name: User-visible name of the addressbook. If the server provides
|
|
||||||
// an additional display name for the addressbooks found for the
|
|
||||||
// preset, it will be appended in brackets to this name, except
|
|
||||||
// if carddav_name_only is true (see below).
|
|
||||||
//
|
|
||||||
// username: CardDAV username to access the addressbook. Set this setting
|
|
||||||
// to '%u' to use the roundcube username.
|
|
||||||
// In case one uses an email address as username there is the
|
|
||||||
// additional option to choose '%l', which will only use the
|
|
||||||
// local part of the username (eg: user.name@example.com will
|
|
||||||
// become user.name).
|
|
||||||
// Also, %d is available to get only the domain part of the
|
|
||||||
// username (eg: user.name@example.com will become example.com).
|
|
||||||
// In some cases %V might be usefull: it replaces @ and . by _.
|
|
||||||
// (eg: user.name@example.com will become user_name_example_com)
|
|
||||||
//
|
|
||||||
// password: CardDAV password to access the addressbook. Set this setting
|
|
||||||
// to '%p' to use the roundcube password. The password will not
|
|
||||||
// be stored in the database when using %p.
|
|
||||||
//
|
|
||||||
// url: URL where to find the CardDAV addressbook(s). If the given URL
|
|
||||||
// refers directly to an addressbook, only this single
|
|
||||||
// addressbook will be added. If the URL points somewhere in the
|
|
||||||
// CardDAV space, but _not_ to the location of a particular
|
|
||||||
// addressbook, the server will be queried for the available
|
|
||||||
// addressbooks and all of them will be added. You can use %u
|
|
||||||
// within the URL as a placeholder for the CardDAV username.
|
|
||||||
// '%l' works the same way as it does for the username field.
|
|
||||||
//
|
|
||||||
// The following parameters are OPTIONAL and need to be specified only if the default
|
|
||||||
// value is not acceptable.
|
|
||||||
//
|
|
||||||
// active: If this parameter is false, the addressbook is not used by roundcube
|
|
||||||
// unless the user changes this setting.
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// carddav_name_only:
|
|
||||||
// If this parameter is true, only the server provided displayname
|
|
||||||
// is used for addressbooks created from this preset, except if
|
|
||||||
// the server does not provide a display name.
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// readonly: If this parameter is true, the addressbook will only be
|
|
||||||
// accessible in read-only mode, i.e., the user will not be able
|
|
||||||
// to add, modify or delete contacts in the addressbook.
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// refresh_time: Time interval for that cached versions of the addressbook
|
|
||||||
// entries should be used, in hours. After this time interval has
|
|
||||||
// passed since the last pull from the server, it will be
|
|
||||||
// refreshed when the addressbook is accessed the next time.
|
|
||||||
// Default: 01:00:00
|
|
||||||
//
|
|
||||||
// use_categories: If this parameter is true, the addressbook will use the
|
|
||||||
// categories as groups unless the user changes this setting.
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// fixed: Array of parameter keys that must not be changed by the user.
|
|
||||||
// Note that only fixed parameters will be automatically updated
|
|
||||||
// for existing addressbooks created from presets. Otherwise the
|
|
||||||
// user may already have changed the setting, and his change
|
|
||||||
// would be lost. You can add any of the above keys, but it the
|
|
||||||
// setting only affects parameters that can be changed via the
|
|
||||||
// settings pane (e.g., readonly cannot be changed by the user
|
|
||||||
// anyway). Still only parameters listed as fixed will
|
|
||||||
// automatically updated if the preset is changed.
|
|
||||||
// Default: empty, all settings modifiable by user
|
|
||||||
//
|
|
||||||
// !!! WARNING: Only add 'url' to the list of fixed addressbooks
|
|
||||||
// if it _directly_ points to an address book collection.
|
|
||||||
// Otherwise, the plugin will initially lookup the URLs for the
|
|
||||||
// collections on the server, and at the next login overwrite it
|
|
||||||
// with the fixed value stored here. Therefore, if you change the
|
|
||||||
// URL, you have two options:
|
|
||||||
// 1) If the new URL is a variation of the old one (e.g. hostname
|
|
||||||
// change), you can run an SQL UPDATE query directly in the
|
|
||||||
// database to adopt all addressbooks.
|
|
||||||
// 2) If the new URL is not easily derivable from the old one,
|
|
||||||
// change the key of the preset and change the URL. Addressbooks
|
|
||||||
// belonging to the old preset will be deleted upon the next
|
|
||||||
// login of the user and freshly created.
|
|
||||||
//
|
|
||||||
// require_always: If set, this database field is required to be non-empty
|
|
||||||
// for ALL queries, even just for displaying members. This may be
|
|
||||||
// useful if you have shared, read-only addressbooks with a lot
|
|
||||||
// of contacts that do not have an email address.
|
|
||||||
//
|
|
||||||
// hide: Whether this preset should be hidden from the CalDAV listing
|
|
||||||
// on the preferences page.
|
|
||||||
|
|
||||||
|
|
||||||
// How Preset Updates work
|
|
||||||
//
|
|
||||||
// Preset addressbooks are created for a user as she logs in.
|
|
||||||
|
|
||||||
//// ** ADDRESSBOOK PRESETS - EXAMPLE: Two Addressbook Presets
|
|
||||||
|
|
||||||
//// Preset 1: Personal
|
|
||||||
/*
|
|
||||||
$prefs['Personal'] = array(
|
|
||||||
// required attributes
|
|
||||||
'name' => 'Personal',
|
|
||||||
// will be substituted for the roundcube username
|
|
||||||
'username' => '%u',
|
|
||||||
// will be substituted for the roundcube password
|
|
||||||
'password' => '%p',
|
|
||||||
// %u will be substituted for the CardDAV username
|
|
||||||
'url' => 'https://ical.example.org/caldav.php/%u/Personal',
|
|
||||||
|
|
||||||
'active' => true,
|
|
||||||
'readonly' => false,
|
|
||||||
'refresh_time' => '02:00:00',
|
|
||||||
|
|
||||||
'fixed' => array( 'username' ),
|
|
||||||
'hide' => false,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
//// Preset 2: Corporate
|
|
||||||
/*
|
|
||||||
$prefs['Work'] = array(
|
|
||||||
'name' => 'Corporate',
|
|
||||||
'username' => 'CorpUser',
|
|
||||||
'password' => 'C0rpPasswo2d',
|
|
||||||
'url' => 'https://ical.example.org/caldav.php/%u/Corporate',
|
|
||||||
|
|
||||||
'fixed' => array( 'name', 'username', 'password' ),
|
|
||||||
'hide' => true,
|
|
||||||
);
|
|
||||||
*/
|
|
@ -1,84 +0,0 @@
|
|||||||
-- table to store the configured address books
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_addressbooks (
|
|
||||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
name VARCHAR(64) NOT NULL,
|
|
||||||
username VARCHAR(64) NOT NULL,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
url VARCHAR(255) NOT NULL,
|
|
||||||
active TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
|
||||||
user_id INT(10) UNSIGNED NOT NULL,
|
|
||||||
last_updated TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:01', -- time stamp of the last update of the local database
|
|
||||||
refresh_time TIME NOT NULL DEFAULT '01:00:00', -- time span after that the local database will be refreshed, default 1h
|
|
||||||
sync_token VARCHAR(255) NOT NULL DEFAULT '', -- sync-token the server sent us for the last sync
|
|
||||||
authentication_scheme VARCHAR(64) NOT NULL DEFAULT "auto", -- the HTTP authentication scheme to use, auto will be overwritten
|
|
||||||
|
|
||||||
presetname VARCHAR(64), -- presetname
|
|
||||||
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
FOREIGN KEY (user_id) REFERENCES TABLE_PREFIXusers(user_id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
) CHARACTER SET utf8 COLLATE utf8_unicode_ci /*!40000 ENGINE=INNODB */;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_contacts (
|
|
||||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
abook_id INT UNSIGNED NOT NULL,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
email VARCHAR(255), -- ", " separated list of mail addresses
|
|
||||||
firstname VARCHAR(255),
|
|
||||||
surname VARCHAR(255),
|
|
||||||
organization VARCHAR(255),
|
|
||||||
showas VARCHAR(32) NOT NULL DEFAULT '', -- special display type (e.g., as a company)
|
|
||||||
vcard LONGTEXT NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
INDEX (abook_id),
|
|
||||||
UNIQUE INDEX(uri,abook_id),
|
|
||||||
UNIQUE INDEX(cuid,abook_id),
|
|
||||||
FOREIGN KEY (abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
) CHARACTER SET utf8 COLLATE utf8_unicode_ci /*!40000 ENGINE=INNODB */;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_xsubtypes (
|
|
||||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
typename VARCHAR(128) NOT NULL, -- name of the type
|
|
||||||
subtype VARCHAR(128) NOT NULL, -- name of the subtype
|
|
||||||
abook_id INT UNSIGNED NOT NULL,
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
UNIQUE INDEX(typename,subtype,abook_id),
|
|
||||||
FOREIGN KEY (abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
) CHARACTER SET utf8 COLLATE utf8_unicode_ci /*!40000 ENGINE=INNODB */;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_groups (
|
|
||||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
abook_id INT UNSIGNED NOT NULL,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
vcard TEXT NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
UNIQUE(uri,abook_id),
|
|
||||||
UNIQUE(cuid,abook_id),
|
|
||||||
|
|
||||||
FOREIGN KEY (abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
) CHARACTER SET utf8 COLLATE utf8_unicode_ci /*!40000 ENGINE=INNODB */;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_group_user (
|
|
||||||
group_id INT UNSIGNED NOT NULL,
|
|
||||||
contact_id INT UNSIGNED NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY(group_id,contact_id),
|
|
||||||
FOREIGN KEY(group_id) REFERENCES TABLE_PREFIXcarddav_groups(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY(contact_id) REFERENCES TABLE_PREFIXcarddav_contacts(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
) CHARACTER SET utf8 COLLATE utf8_unicode_ci /*!40000 ENGINE=INNODB */;
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_migrations (
|
|
||||||
`ID` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
|
||||||
`filename` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
|
|
||||||
`processed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
|
|
||||||
UNIQUE (
|
|
||||||
`filename`
|
|
||||||
)
|
|
||||||
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
|
|
@ -1,105 +0,0 @@
|
|||||||
CREATE SEQUENCE TABLE_PREFIXcarddav_addressbooks_seq
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MAXVALUE
|
|
||||||
MINVALUE 1
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
-- table to store the configured address books
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_addressbooks (
|
|
||||||
id integer DEFAULT nextval('TABLE_PREFIXcarddav_addressbooks_seq'::text) PRIMARY KEY,
|
|
||||||
name VARCHAR(64) NOT NULL,
|
|
||||||
username VARCHAR(64) NOT NULL,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
url VARCHAR(255) NOT NULL,
|
|
||||||
active SMALLINT NOT NULL DEFAULT 1,
|
|
||||||
user_id integer NOT NULL REFERENCES TABLE_PREFIXusers (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
last_updated TIMESTAMP NOT NULL DEFAULT '-infinity', -- time stamp of the last update of the local database
|
|
||||||
refresh_time INTERVAL NOT NULL DEFAULT '01:00:00', -- time span after that the local database will be refreshed, default 1h
|
|
||||||
sync_token VARCHAR(255) NOT NULL DEFAULT '', -- sync-token the server sent us for the last sync
|
|
||||||
authentication_scheme VARCHAR(64) NOT NULL DEFAULT 'auto', -- the HTTP authentication scheme to use, auto will be overwritten
|
|
||||||
|
|
||||||
presetname VARCHAR(64) -- presetname
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE SEQUENCE TABLE_PREFIXcarddav_contacts_seq
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MAXVALUE
|
|
||||||
MINVALUE 1
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_contacts (
|
|
||||||
id integer DEFAULT nextval('TABLE_PREFIXcarddav_contacts_seq'::text) PRIMARY KEY,
|
|
||||||
abook_id integer NOT NULL REFERENCES TABLE_PREFIXcarddav_addressbooks (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
email VARCHAR(255), -- ", " separated list of mail addresses
|
|
||||||
firstname VARCHAR(255),
|
|
||||||
surname VARCHAR(255),
|
|
||||||
organization VARCHAR(255),
|
|
||||||
showas VARCHAR(32) NOT NULL DEFAULT '', -- special display type (e.g., as a company)
|
|
||||||
vcard text NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
UNIQUE(uri,abook_id),
|
|
||||||
UNIQUE(cuid,abook_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX TABLE_PREFIXcarddav_contacts_abook_id_idx ON TABLE_PREFIXcarddav_contacts(abook_id);
|
|
||||||
|
|
||||||
CREATE SEQUENCE TABLE_PREFIXcarddav_xsubtypes_seq
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MAXVALUE
|
|
||||||
MINVALUE 1
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_xsubtypes (
|
|
||||||
id integer DEFAULT nextval('TABLE_PREFIXcarddav_xsubtypes_seq'::text) PRIMARY KEY,
|
|
||||||
typename VARCHAR(128) NOT NULL, -- name of the type
|
|
||||||
subtype VARCHAR(128) NOT NULL, -- name of the subtype
|
|
||||||
abook_id integer NOT NULL REFERENCES TABLE_PREFIXcarddav_addressbooks (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
UNIQUE (typename,subtype,abook_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE SEQUENCE TABLE_PREFIXcarddav_groups_seq
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MAXVALUE
|
|
||||||
MINVALUE 1
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_groups (
|
|
||||||
id integer DEFAULT nextval('TABLE_PREFIXcarddav_groups_seq'::text) PRIMARY KEY,
|
|
||||||
abook_id integer NOT NULL REFERENCES TABLE_PREFIXcarddav_addressbooks (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
vcard TEXT NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
UNIQUE(uri,abook_id),
|
|
||||||
UNIQUE(cuid,abook_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_group_user (
|
|
||||||
group_id integer NOT NULL,
|
|
||||||
contact_id integer NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY(group_id,contact_id),
|
|
||||||
FOREIGN KEY(group_id) REFERENCES TABLE_PREFIXcarddav_groups(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY(contact_id) REFERENCES TABLE_PREFIXcarddav_contacts(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE SEQUENCE TABLE_PREFIXcarddav_migrations_seq
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MAXVALUE
|
|
||||||
MINVALUE 1
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
CREATE TABLE TABLE_PREFIXcarddav_migrations (
|
|
||||||
ID integer DEFAULT nextval('TABLE_PREFIXcarddav_migrations_seq'::text) PRIMARY KEY,
|
|
||||||
filename VARCHAR(64) NOT NULL,
|
|
||||||
processed_at TIMESTAMP NOT NULL DEFAULT now(),
|
|
||||||
|
|
||||||
UNIQUE(filename)
|
|
||||||
);
|
|
@ -1,89 +0,0 @@
|
|||||||
-- table to store the finished migrations
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_migrations (
|
|
||||||
ID integer NOT NULL PRIMARY KEY,
|
|
||||||
filename VARCHAR(64) NOT NULL,
|
|
||||||
processed_at TIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
UNIQUE(filename)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- table to store the configured address books
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_addressbooks (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
name VARCHAR(64) NOT NULL,
|
|
||||||
username VARCHAR(64) NOT NULL,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
url VARCHAR(255) NOT NULL,
|
|
||||||
active TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
|
||||||
user_id integer NOT NULL,
|
|
||||||
last_updated DATETIME NOT NULL DEFAULT 0, -- time stamp of the last update of the local database
|
|
||||||
refresh_time TIME NOT NULL DEFAULT '01:00:00', -- time span after that the local database will be refreshed
|
|
||||||
sync_token VARCHAR(255) NOT NULL DEFAULT '', -- sync-token the server sent us for the last sync
|
|
||||||
authentication_scheme VARCHAR(64) NOT NULL DEFAULT "auto", -- the HTTP authentication scheme to use, auto will be overwritten
|
|
||||||
|
|
||||||
presetname VARCHAR(64), -- presetname
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(user_id) REFERENCES TABLE_PREFIXusers(user_id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_contacts (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
abook_id integer NOT NULL,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
email VARCHAR(255), -- ", " separated list of mail addresses
|
|
||||||
firstname VARCHAR(255),
|
|
||||||
surname VARCHAR(255),
|
|
||||||
organization VARCHAR(255),
|
|
||||||
showas VARCHAR(32) NOT NULL DEFAULT '', -- special display type (e.g., as a company)
|
|
||||||
vcard TEXT NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
UNIQUE(uri,abook_id),
|
|
||||||
UNIQUE(cuid,abook_id),
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
CREATE INDEX TABLE_PREFIXcarddav_contacts_abook_id_idx ON TABLE_PREFIXcarddav_contacts(abook_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_xsubtypes (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
typename VARCHAR(128) NOT NULL, -- name of the type
|
|
||||||
subtype VARCHAR(128) NOT NULL, -- name of the subtype
|
|
||||||
abook_id integer NOT NULL,
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
UNIQUE(typename,subtype,abook_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_groups (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
abook_id integer NOT NULL,
|
|
||||||
name VARCHAR(255) NOT NULL, -- display name
|
|
||||||
vcard TEXT NOT NULL, -- complete vcard
|
|
||||||
etag VARCHAR(255) NOT NULL, -- entity tag, can be used to check if card changed on server
|
|
||||||
uri VARCHAR(255) NOT NULL, -- path of the card on the server
|
|
||||||
cuid VARCHAR(255) NOT NULL, -- unique identifier of the card within the collection
|
|
||||||
|
|
||||||
UNIQUE(uri,abook_id),
|
|
||||||
UNIQUE(cuid,abook_id),
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(abook_id) REFERENCES TABLE_PREFIXcarddav_addressbooks(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_group_user (
|
|
||||||
group_id integer NOT NULL,
|
|
||||||
contact_id integer NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY(group_id,contact_id),
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(group_id) REFERENCES TABLE_PREFIXcarddav_groups(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY(contact_id) REFERENCES TABLE_PREFIXcarddav_contacts(id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD `use_categories` INT NOT NULL DEFAULT '0' AFTER `presetname`;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD COLUMN use_categories SMALLINT NOT NULL DEFAULT 0;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD use_categories TINYINT NOT NULL DEFAULT 0;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `username` VARCHAR(255);
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `presetname` VARCHAR(255);
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ALTER COLUMN username TYPE VARCHAR(255);
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ALTER COLUMN presetname TYPE VARCHAR(255);
|
|
@ -1,32 +0,0 @@
|
|||||||
PRAGMA foreign_keys=OFF;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS TABLE_PREFIXcarddav_addressbooks_X (
|
|
||||||
id integer NOT NULL PRIMARY KEY,
|
|
||||||
name VARCHAR(64) NOT NULL,
|
|
||||||
username VARCHAR(255) NOT NULL,
|
|
||||||
password VARCHAR(255) NOT NULL,
|
|
||||||
url VARCHAR(255) NOT NULL,
|
|
||||||
active TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
|
||||||
user_id integer NOT NULL,
|
|
||||||
last_updated DATETIME NOT NULL DEFAULT 0, -- time stamp of the last update of the local database
|
|
||||||
refresh_time TIME NOT NULL DEFAULT '01:00:00', -- time span after that the local database will be refreshed
|
|
||||||
sync_token VARCHAR(255) NOT NULL DEFAULT '', -- sync-token the server sent us for the last sync
|
|
||||||
authentication_scheme VARCHAR(64) NOT NULL DEFAULT "auto", -- the HTTP authentication scheme to use, auto will be overwritten
|
|
||||||
|
|
||||||
presetname VARCHAR(255), -- presetname
|
|
||||||
|
|
||||||
use_categories TINYINT NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
-- not enforced by sqlite < 3.6.19
|
|
||||||
FOREIGN KEY(user_id) REFERENCES TABLE_PREFIXusers(user_id) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
INSERT INTO TABLE_PREFIXcarddav_addressbooks_X SELECT * FROM TABLE_PREFIXcarddav_addressbooks;
|
|
||||||
|
|
||||||
DROP TABLE TABLE_PREFIXcarddav_addressbooks;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks_X RENAME TO TABLE_PREFIXcarddav_addressbooks;
|
|
||||||
|
|
||||||
PRAGMA foreign_key_check;
|
|
||||||
|
|
||||||
PRAGMA foreign_keys=ON;
|
|
@ -1 +0,0 @@
|
|||||||
This migration has been disabled because it was broken. It got fixed and replaced by 0004-fixtimestampdefaultvalue.
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `last_updated` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:01';
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1,56 +0,0 @@
|
|||||||
-- table to store the configured address books
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks DROP INDEX `user_id`, ADD UNIQUE `user_id` (`user_id`, `presetname`(191)) USING BTREE;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `username` `username` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `password` `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `url` `url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `sync_token` `sync_token` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `authentication_scheme` `authentication_scheme` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks CHANGE `presetname` `presetname` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts DROP INDEX `uri`, ADD UNIQUE `uri` (`uri`(191), `abook_id`) USING BTREE;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts DROP INDEX `cuid`, ADD UNIQUE `cuid` (`cuid`(191), `abook_id`) USING BTREE;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `email` `email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `firstname` `firstname` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `surname` `surname` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `organization` `organization` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `showas` `showas` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `vcard` `vcard` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `etag` `etag` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `uri` `uri` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_contacts CHANGE `cuid` `cuid` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups DROP INDEX `uri`, ADD UNIQUE `uri` (`uri`(191), `abook_id`) USING BTREE;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups DROP INDEX `cuid`, ADD UNIQUE `cuid` (`cuid`(191), `abook_id`) USING BTREE;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups CHANGE `etag` `etag` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups CHANGE `uri` `uri` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_groups CHANGE `cuid` `cuid` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_group_user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_migrations CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_migrations CHANGE `filename` `filename` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_xsubtypes CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_xsubtypes CHANGE `typename` `typename` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
ALTER TABLE TABLE_PREFIXcarddav_xsubtypes CHANGE `subtype` `subtype` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_addressbooks;
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_contacts;
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_groups;
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_group_user;
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_migrations;
|
|
||||||
REPAIR TABLE TABLE_PREFIXcarddav_xsubtypes;
|
|
||||||
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_addressbooks;
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_contacts;
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_groups;
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_group_user;
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_migrations;
|
|
||||||
OPTIMIZE TABLE TABLE_PREFIXcarddav_xsubtypes;
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1 +0,0 @@
|
|||||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Aktivovat adresář kontaktů CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Přidat nový adresář kontaktů CardDAV",
|
|
||||||
'cd_username'=> "Uživatel",
|
|
||||||
'cd_password'=> "Heslo",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "\"Nainstalovaná verze PHP je zastaralá. Aktualizujte PHP na verzi 5.6.18 nebo vyšší! V současnosti máte nainstalovanou následující verzi:",
|
|
||||||
'cd_name'=> "Název adresáře kontaktů CardDAV",
|
|
||||||
'cd_delete'=> "Odstranit tento adresář kontaktů",
|
|
||||||
'cd_name_new'=> "Nastavit nový adresář kontaktů",
|
|
||||||
'cd_refresh_time'=> "Interval aktualizace (hodiny)",
|
|
||||||
'cd_err_noabfound'=> "no addressbook found",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "CardDAV-Adressbuch aktivieren",
|
|
||||||
'cd_newabboxtitle'=> "Neues Adressbuch hinzufügen",
|
|
||||||
'cd_username'=> "Benutzername",
|
|
||||||
'cd_password'=> "Passwort",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Ihre PHP Version ist zu alt! Es wird mindestens 5.6.18 benoetigt! Sie haben folgende Version installiert:",
|
|
||||||
'cd_name'=> "Name des Adressbuches",
|
|
||||||
'cd_use_categories' => "Modernen Gruppenmechanismus verwenden\n(Alte RCMCardDAV Gruppen gehen verloren!)",
|
|
||||||
'cd_delete'=> "Dieses Adressbuch entfernen",
|
|
||||||
'cd_name_new'=> "Neues Adressbuch konfigurieren",
|
|
||||||
'cd_refresh_time'=> "Aktualisierungsintervall (Stunden)",
|
|
||||||
'cd_err_noabfound'=> "Kein Adressbuch gefunden.",
|
|
||||||
'cd_preemptive_auth'=> "Immer am Server authentifizieren. Für ownCloud aktivieren!",
|
|
||||||
'cd_enabled' => 'Aktiv',
|
|
||||||
'cd_disabled' => 'Inaktiv',
|
|
||||||
'cd_frompreset' => ' (aus Vorgabe _PRESETNAME_)',
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title' => 'CardDAV',
|
|
||||||
'cd_active' => 'Activate CardDAV-Addressbook',
|
|
||||||
'cd_newabboxtitle'=> "Add new addressbook",
|
|
||||||
'cd_username' => 'Username',
|
|
||||||
'cd_password' => 'Password',
|
|
||||||
'cd_url' => 'URL',
|
|
||||||
'cd_php_too_old' => "Your version of PHP is too old! Please update to at least 5.6.18! You got the following version installed:",
|
|
||||||
'cd_name' => "Name of the addressbook",
|
|
||||||
'cd_use_categories' => "Use modern group mechanism\n(you will lose old RCMCardDAV groups!)",
|
|
||||||
'cd_delete' => "Remove this addressbook",
|
|
||||||
'cd_name_new' => "Configure new addressbook",
|
|
||||||
'cd_refresh_time' => "Update interval (hours)",
|
|
||||||
'cd_err_noabfound' => 'no addressbook found',
|
|
||||||
'cd_preemptive_auth' => 'Preemptively authenticate against server. Use for ownCloud!',
|
|
||||||
'cd_enabled' => 'Enabled',
|
|
||||||
'cd_disabled' => 'Disabled',
|
|
||||||
'cd_frompreset' => ' (from preset _PRESETNAME_)',
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Activar Libreta de Direcciones CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Añadir nueva Libreta de Direcciones",
|
|
||||||
'cd_username'=> "Nombre de usuario",
|
|
||||||
'cd_password'=> "Contraseña",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "La versión de PHP es demasiado antigua! Por favor, actualiza al menos a la 5.6.18! La versión instalada es la siguiente:",
|
|
||||||
'cd_name'=> "Nombre de la libreta de direcciones",
|
|
||||||
'cd_delete'=> "Eliminar esta libreta de direcciones",
|
|
||||||
'cd_name_new'=> "Configurar una nueva libreta de direcciones",
|
|
||||||
'cd_refresh_time'=> "Intervalo de actualización (horas)",
|
|
||||||
'cd_err_noabfound'=> "libreta de direcciones no encontrada",
|
|
||||||
'cd_preemptive_auth'=> "Autenticar previamente contra el servidor. Necesario para OwnCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Activer ce carnet d'adresses",
|
|
||||||
'cd_newabboxtitle'=> "Ajouter un nouveau carnet d'adresses",
|
|
||||||
'cd_username'=> "Nom d'utilisateur",
|
|
||||||
'cd_password'=> "Mot de passe",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Votre version de PHP est trop ancienne. Veuillez mettre à jour avec la version 5.6.18 minimum! La version actuellement installée est :",
|
|
||||||
'cd_name'=> "Nom du carnet d'adresses",
|
|
||||||
'cd_use_categories' => "Utilise les categories comme des groupes",
|
|
||||||
'cd_delete'=> "Supprimer ce carnet d'adresses",
|
|
||||||
'cd_name_new'=> "Ajouter un nouveau carnet d'adresses",
|
|
||||||
'cd_refresh_time'=> "Validité du cache local (en heures)",
|
|
||||||
'cd_err_noabfound'=> "Aucun carnet d'adresses trouvé",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
'cd_enabled'=>'Activé',
|
|
||||||
'cd_disabled'=>'Désactivé',
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "CardDAV címjegyzék aktiválása",
|
|
||||||
'cd_newabboxtitle'=> "Add new addressbook",
|
|
||||||
'cd_username'=> "Felhasználónév",
|
|
||||||
'cd_password'=> "Jelszó",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "A PHP verziód túl régi, e program futásához legalább 5.6.18-ás verzióra van szükség. A jelenlegi PHP verzió:",
|
|
||||||
'cd_name'=> "Címjegyzék neve",
|
|
||||||
'cd_delete'=> "Címjegyzék törlése",
|
|
||||||
'cd_name_new'=> "Címjegyzék beállításai",
|
|
||||||
'cd_refresh_time'=> "Frissítési intervallum (óra)",
|
|
||||||
'cd_err_noabfound'=> "no addressbook found",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Aktifkan buku alamat berbasis CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Add new addressbook",
|
|
||||||
'cd_username'=> "Nama pengguna",
|
|
||||||
'cd_password'=> "Kata sandi",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Versi PHP yang digunakan adalah versi yang terlalu tua! Mohon di-update sedikitnya ke versi 5.6.18! Versi PHP yang digunakan oleh Anda:",
|
|
||||||
'cd_name'=> "Nama buku alamat",
|
|
||||||
'cd_delete'=> "Menghapuskan buku alamat ini",
|
|
||||||
'cd_name_new'=> "Mengkonfigurasi buku alamat baru",
|
|
||||||
'cd_refresh_time'=> "Interval update (dalam jam)",
|
|
||||||
'cd_err_noabfound'=> "no addressbook found",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Utilizza rubrica CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Aggiungi una nuova Rubrica",
|
|
||||||
'cd_username'=> "Nome utente",
|
|
||||||
'cd_password'=> "Password",
|
|
||||||
'cd_url'=> "Indirizzo server (URL)",
|
|
||||||
'cd_php_too_old'=> "E' necessario aggiornare PHP alla versione 5.6.18 o superiore! Attualmente hai la versione:",
|
|
||||||
'cd_name'=> "Nome nuova rubrica",
|
|
||||||
'cd_delete'=> "Elimina rubrica",
|
|
||||||
'cd_name_new'=> "Crea una nuova rubrica",
|
|
||||||
'cd_refresh_time'=> "Frequenza di aggiornamento (ore)",
|
|
||||||
'cd_err_noabfound'=> "Nessuna Rubrica Trovata",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Aktywuj książkę adresową CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Dodaj nową książkę adresową",
|
|
||||||
'cd_username'=> "Nazwa użytkownika",
|
|
||||||
'cd_password'=> "Hasło",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Twoja wersja PHP jest nieaktualna! Proszę zaktualizuj do minimum wersji 5.6.18! Twoja wersja to:",
|
|
||||||
'cd_name'=> "Nazwa książki adresowej",
|
|
||||||
'cd_use_categories' => "Użyj nowego mechanizmu grup\n(stracisz stare grupy RCMCardDAV!)",
|
|
||||||
'cd_delete'=> "Usuń książkę adresową",
|
|
||||||
'cd_name_new'=> "Konfiguracja nowej książki adresowej",
|
|
||||||
'cd_refresh_time'=> "Interwał aktualizacji (godziny)",
|
|
||||||
'cd_err_noabfound'=> "nie znaleziono książek adresowych",
|
|
||||||
'cd_preemptive_auth'=> "Zapobiegawczo uwierzytelnij z serwerem. Używaj dla ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Активировать адресную книгу CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Добавить новую адресную книгу",
|
|
||||||
'cd_username'=> "Имя пользователя",
|
|
||||||
'cd_password'=> "Пароль",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Ваша версия PHP слишком устарела! Пожалуйста, обновитесь по крайней мере до 5.6.18! У Вас установлена следующая версия: ",
|
|
||||||
'cd_name'=> "Название адресной книги",
|
|
||||||
'cd_delete'=> "Удалить адресную книгу",
|
|
||||||
'cd_name_new'=> "Настроить новую адресную книгу",
|
|
||||||
'cd_refresh_time'=> "Частота обновления (часов)",
|
|
||||||
'cd_err_noabfound'=> "Не найдено ни одной адресной книги",
|
|
||||||
'cd_preemptive_auth'=> "Предварительно авторизоваться на сервере. Используйте с ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Aktivera CardDAV-adressboken",
|
|
||||||
'cd_newabboxtitle'=> "Add new addressbook",
|
|
||||||
'cd_username'=> "Användarnamn",
|
|
||||||
'cd_password'=> "Lösenord",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Din version av PHP är för gammal! Vänligen uppdatera till åtminstone 5.0.3! Du har följande version installerad: ",
|
|
||||||
'cd_name'=> "Namn på adressboken",
|
|
||||||
'cd_delete'=> "Radera denna adressbok",
|
|
||||||
'cd_name_new'=> "Konfigurera en ny addressbok",
|
|
||||||
'cd_refresh_time'=> "Uppdateringsintervall (timmar)",
|
|
||||||
'cd_err_noabfound'=> "no addressbook found",
|
|
||||||
'cd_preemptive_auth'=> "Preemptively authenticate against server. Use for ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
$labels = Array(
|
|
||||||
'cd_title'=> "CardDAV",
|
|
||||||
'cd_active'=> "Увімкнути список контактів CardDAV",
|
|
||||||
'cd_newabboxtitle'=> "Додати новий список контактів",
|
|
||||||
'cd_username'=> "Ім'я користувача",
|
|
||||||
'cd_password'=> "Пароль",
|
|
||||||
'cd_url'=> "URL",
|
|
||||||
'cd_php_too_old'=> "Ваша версія PHP занадто стара! Будь ласка, оновіть її принаймні до 5.6.18! У Вас встановлена така версія:",
|
|
||||||
'cd_name'=> "Назва списку контактів",
|
|
||||||
'cd_delete'=> "Видалити цей список контактів",
|
|
||||||
'cd_name_new'=> "Налаштувати цей список контактів",
|
|
||||||
'cd_refresh_time'=> "Період оновлення (в годинах)",
|
|
||||||
'cd_err_noabfound'=> "не знайдено жодного списку контактів",
|
|
||||||
'cd_preemptive_auth'=> "Попередньо авторизуватись на сервері. Використовуйте для ownCloud!",
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1,75 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
|
||||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
|
||||||
http://pear.php.net/dtd/package-2.0
|
|
||||||
http://pear.php.net/dtd/package-2.0.xsd">
|
|
||||||
<name>carddav</name>
|
|
||||||
<channel>www.benjamin-schieder.de</channel>
|
|
||||||
<summary>CardDAV plugin for Roundcube</summary>
|
|
||||||
<description>
|
|
||||||
Adds functionality to use, synchronize and manipulate CardDAV accounts with Roundcube.
|
|
||||||
Tested with davical, owncloud, MacOS Addressbook and others.
|
|
||||||
</description>
|
|
||||||
<lead>
|
|
||||||
<name>Benjamin Schieder</name>
|
|
||||||
<user>blindcoder</user>
|
|
||||||
<email>carddav@wegwerf.anderdonau.de</email>
|
|
||||||
<active>yes</active>
|
|
||||||
</lead>
|
|
||||||
<developer>
|
|
||||||
<name>Michael Stilkerich</name>
|
|
||||||
<user>mike2k</user>
|
|
||||||
<email>ms@mike2k.de</email>
|
|
||||||
<active>yes</active>
|
|
||||||
</developer>
|
|
||||||
<date>2018-10-01</date>
|
|
||||||
<version>
|
|
||||||
<release>3.0.3</release>
|
|
||||||
</version>
|
|
||||||
<stability>
|
|
||||||
<release>stable</release>
|
|
||||||
</stability>
|
|
||||||
<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
|
|
||||||
<notes>-</notes>
|
|
||||||
<contents>
|
|
||||||
<dir baseinstalldir="/" name="/">
|
|
||||||
<file name="carddav_discovery.php" role="php">
|
|
||||||
<tasks:replace from="@name@" to="name" type="package-info"/>
|
|
||||||
<tasks:replace from="@package_version@" to="version" type="package-info"/>
|
|
||||||
</file>
|
|
||||||
<file name="carddav_common.php" role="php">
|
|
||||||
<tasks:replace from="@name@" to="name" type="package-info"/>
|
|
||||||
<tasks:replace from="@package_version@" to="version" type="package-info"/>
|
|
||||||
</file>
|
|
||||||
<file name="carddav_backend.php" role="php">
|
|
||||||
<tasks:replace from="@name@" to="name" type="package-info"/>
|
|
||||||
<tasks:replace from="@package_version@" to="version" type="package-info"/>
|
|
||||||
</file>
|
|
||||||
<file name="carddav.php" role="php">
|
|
||||||
<tasks:replace from="@name@" to="name" type="package-info"/>
|
|
||||||
<tasks:replace from="@package_version@" to="version" type="package-info"/>
|
|
||||||
</file>
|
|
||||||
<file name="localization/cs_CZ.inc" role="data"></file>
|
|
||||||
<file name="localization/de_DE.inc" role="data"></file>
|
|
||||||
<file name="localization/en_US.inc" role="data"></file>
|
|
||||||
<file name="localization/es_ES.inc" role="data"></file>
|
|
||||||
<file name="localization/fr_FR.inc" role="data"></file>
|
|
||||||
<file name="localization/hu_HU.inc" role="data"></file>
|
|
||||||
<file name="localization/id_ID.inc" role="data"></file>
|
|
||||||
<file name="localization/it_IT.inc" role="data"></file>
|
|
||||||
<file name="localization/pl_PL.inc" role="data"></file>
|
|
||||||
<file name="localization/ru_RU.inc" role="data"></file>
|
|
||||||
<file name="localization/sv_SE.inc" role="data"></file>
|
|
||||||
<file name="localization/uk_UK.inc" role="data"></file>
|
|
||||||
</dir>
|
|
||||||
<!-- / -->
|
|
||||||
</contents>
|
|
||||||
<dependencies>
|
|
||||||
<required>
|
|
||||||
<php>
|
|
||||||
<min>5.6.18</min>
|
|
||||||
</php>
|
|
||||||
</required>
|
|
||||||
</dependencies>
|
|
||||||
<phprelease/>
|
|
||||||
</package>
|
|
@ -1,6 +0,0 @@
|
|||||||
#sections-table #rcmrowcd_preferences td.section {
|
|
||||||
background-position: 6px -766px;
|
|
||||||
}
|
|
||||||
#sections-table #rcmrowcd_preferences.selected td.section {
|
|
||||||
background-position: 6px -791px;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
.listing.iconized tr.cd_preferences>td.section:before {
|
|
||||||
content: "\f47f"
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
#sections-table #rcmrowcd_preferences td.section {
|
|
||||||
background-position: 6px -766px;
|
|
||||||
}
|
|
||||||
#sections-table #rcmrowcd_preferences.selected td.section {
|
|
||||||
background-position: 6px -791px;
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// managesieve server port. When empty the port will be determined automatically
|
|
||||||
// using getservbyname() function, with 4190 as a fallback.
|
|
||||||
// $config['managesieve_port'] = null;
|
|
||||||
$config['managesieve_port'] = 4190;
|
|
||||||
|
|
||||||
// managesieve server address, default is localhost.
|
|
||||||
// Replacement variables supported in host name:
|
|
||||||
// %h - user's IMAP hostname
|
|
||||||
// %n - http hostname ($_SERVER['SERVER_NAME'])
|
|
||||||
// %d - domain (http hostname without the first part)
|
|
||||||
// For example %n = mail.domain.tld, %d = domain.tld
|
|
||||||
$config['managesieve_host'] = '%h';
|
|
||||||
|
|
||||||
// authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL
|
|
||||||
// or none. Optional, defaults to best method supported by server.
|
|
||||||
$config['managesieve_auth_type'] = null;
|
|
||||||
|
|
||||||
// Optional managesieve authentication identifier to be used as authorization proxy.
|
|
||||||
// Authenticate as a different user but act on behalf of the logged in user.
|
|
||||||
// Works with PLAIN and DIGEST-MD5 auth.
|
|
||||||
$config['managesieve_auth_cid'] = null;
|
|
||||||
|
|
||||||
// Optional managesieve authentication password to be used for imap_auth_cid
|
|
||||||
$config['managesieve_auth_pw'] = null;
|
|
||||||
|
|
||||||
// use or not TLS for managesieve server connection
|
|
||||||
// Note: tls:// prefix in managesieve_host is also supported
|
|
||||||
// $config['managesieve_usetls'] = false;
|
|
||||||
$config['managesieve_usetls'] = true;
|
|
||||||
|
|
||||||
// Connection scket context options
|
|
||||||
// See http://php.net/manual/en/context.ssl.php
|
|
||||||
// The example below enables server certificate validation
|
|
||||||
//$config['managesieve_conn_options'] = array(
|
|
||||||
// 'ssl' => array(
|
|
||||||
// 'verify_peer' => true,
|
|
||||||
// 'verify_depth' => 3,
|
|
||||||
// 'cafile' => '/etc/openssl/certs/ca.crt',
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// Note: These can be also specified as an array of options indexed by hostname
|
|
||||||
$config['managesieve_conn_options'] = null;
|
|
||||||
|
|
||||||
// default contents of filters script (eg. default spam filter)
|
|
||||||
$config['managesieve_default'] = '/etc/dovecot/sieve/global';
|
|
||||||
|
|
||||||
// The name of the script which will be used when there's no user script
|
|
||||||
$config['managesieve_script_name'] = 'managesieve';
|
|
||||||
|
|
||||||
// Sieve RFC says that we should use UTF-8 endcoding for mailbox names,
|
|
||||||
// but some implementations does not covert UTF-8 to modified UTF-7.
|
|
||||||
// Defaults to UTF7-IMAP
|
|
||||||
$config['managesieve_mbox_encoding'] = 'UTF-8';
|
|
||||||
|
|
||||||
// I need this because my dovecot (with listescape plugin) uses
|
|
||||||
// ':' delimiter, but creates folders with dot delimiter
|
|
||||||
$config['managesieve_replace_delimiter'] = '';
|
|
||||||
|
|
||||||
// disabled sieve extensions (body, copy, date, editheader, encoded-character,
|
|
||||||
// envelope, environment, ereject, fileinto, ihave, imap4flags, index,
|
|
||||||
// mailbox, mboxmetadata, regex, reject, relational, servermetadata,
|
|
||||||
// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc.
|
|
||||||
// Note: not all extensions are implemented
|
|
||||||
$config['managesieve_disabled_extensions'] = array();
|
|
||||||
|
|
||||||
// Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve
|
|
||||||
$config['managesieve_debug'] = false;
|
|
||||||
|
|
||||||
// Enables features described in http://wiki.kolab.org/KEP:14
|
|
||||||
$config['managesieve_kolab_master'] = false;
|
|
||||||
|
|
||||||
// Script name extension used for scripts including. Dovecot uses '.sieve',
|
|
||||||
// Cyrus uses '.siv'. Doesn't matter if you have managesieve_kolab_master disabled.
|
|
||||||
$config['managesieve_filename_extension'] = '.sieve';
|
|
||||||
|
|
||||||
// List of reserved script names (without extension).
|
|
||||||
// Scripts listed here will be not presented to the user.
|
|
||||||
$config['managesieve_filename_exceptions'] = array();
|
|
||||||
|
|
||||||
// List of domains limiting destination emails in redirect action
|
|
||||||
// If not empty, user will need to select domain from a list
|
|
||||||
$config['managesieve_domains'] = array();
|
|
||||||
|
|
||||||
// Enables separate management interface for vacation responses (out-of-office)
|
|
||||||
// 0 - no separate section (default),
|
|
||||||
// 1 - add Vacation section,
|
|
||||||
// 2 - add Vacation section, but hide Filters section
|
|
||||||
$config['managesieve_vacation'] = 0;
|
|
||||||
|
|
||||||
// Default vacation interval (in days).
|
|
||||||
// Note: If server supports vacation-seconds extension it is possible
|
|
||||||
// to define interval in seconds here (as a string), e.g. "3600s".
|
|
||||||
$config['managesieve_vacation_interval'] = 0;
|
|
||||||
|
|
||||||
// Some servers require vacation :addresses to be filled with all
|
|
||||||
// user addresses (aliases). This option enables automatic filling
|
|
||||||
// of these on initial vacation form creation.
|
|
||||||
$config['managesieve_vacation_addresses_init'] = false;
|
|
||||||
|
|
||||||
// Sometimes you want to always reply with mail email address
|
|
||||||
// This option enables automatic filling of :from field on initial vacation form creation.
|
|
||||||
$config['managesieve_vacation_from_init'] = false;
|
|
||||||
|
|
||||||
// Supported methods of notify extension. Default: 'mailto'
|
|
||||||
$config['managesieve_notify_methods'] = array('mailto');
|
|
||||||
|
|
||||||
// Enables scripts RAW editor feature
|
|
||||||
$config['managesieve_raw_editor'] = true;
|
|
@ -1,101 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
+-----------------------------------------------------------------------+
|
|
||||||
| Local configuration for the Roundcube Webmail installation. |
|
|
||||||
| |
|
|
||||||
| This is a sample configuration file only containing the minimum |
|
|
||||||
| setup required for a functional installation. Copy more options |
|
|
||||||
| from defaults.inc.php to this file to override the defaults. |
|
|
||||||
| |
|
|
||||||
| This file is part of the Roundcube Webmail client |
|
|
||||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
|
||||||
| |
|
|
||||||
| Licensed under the GNU General Public License version 3 or |
|
|
||||||
| any later version with exceptions for skins & plugins. |
|
|
||||||
| See the README file for a full license statement. |
|
|
||||||
+-----------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
$config = array();
|
|
||||||
|
|
||||||
$config['auto_create_user'] = true;
|
|
||||||
|
|
||||||
/* Do not set db_dsnw here, use dpkg-reconfigure roundcube-core to configure database ! */
|
|
||||||
// include_once("/etc/roundcube/debian-db-roundcube.php");
|
|
||||||
$config['db_dsnw'] = 'sqlite:////var/db/roundcube.db?mode=0640';
|
|
||||||
|
|
||||||
// The mail host chosen to perform the log-in.
|
|
||||||
// Leave blank to show a textbox at login, give a list of hosts
|
|
||||||
// to display a pulldown menu or set one host as string.
|
|
||||||
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
|
|
||||||
// Supported replacement variables:
|
|
||||||
// %n - hostname ($_SERVER['SERVER_NAME'])
|
|
||||||
// %t - hostname without the first part
|
|
||||||
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
|
|
||||||
// %s - domain name after the '@' from e-mail address provided at login screen
|
|
||||||
// For example %n = mail.domain.tld, %t = domain.tld
|
|
||||||
//$config['default_host'] = '';
|
|
||||||
$config['default_host'] = array(
|
|
||||||
'192.168.50.61' => 'toptica',
|
|
||||||
'ssl://imap.gmx.net' => 'GMX',
|
|
||||||
'ssl://imap.web.de' => 'Web',
|
|
||||||
);
|
|
||||||
|
|
||||||
// SMTP server host (for sending mails).
|
|
||||||
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
|
|
||||||
// If left blank, the PHP mail() function is used
|
|
||||||
// Supported replacement variables:
|
|
||||||
// %h - user's IMAP hostname
|
|
||||||
// %n - hostname ($_SERVER['SERVER_NAME'])
|
|
||||||
// %t - hostname without the first part
|
|
||||||
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
|
|
||||||
// %z - IMAP domain (IMAP hostname without the first part)
|
|
||||||
// For example %n = mail.domain.tld, %t = domain.tld
|
|
||||||
//$config['smtp_server'] = 'mail.lima-city.de';
|
|
||||||
|
|
||||||
// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
|
|
||||||
// deprecated SSL over SMTP (aka SMTPS))
|
|
||||||
$config['smtp_port'] = 25;
|
|
||||||
|
|
||||||
// SMTP username (if required) if you use %u as the username Roundcube
|
|
||||||
// will use the current username for login
|
|
||||||
// $config['smtp_user'] = '';
|
|
||||||
|
|
||||||
// SMTP password (if required) if you use %p as the password Roundcube
|
|
||||||
// will use the current user's password for login
|
|
||||||
// $config['smtp_pass'] = '';
|
|
||||||
|
|
||||||
// provide an URL where a user can get support for this Roundcube installation
|
|
||||||
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
|
|
||||||
//$config['support_url'] = 'https://web.hilie.de/roundcube';
|
|
||||||
|
|
||||||
// Name your service. This is displayed on the login screen and in the window title
|
|
||||||
$config['product_name'] = 'Roundcube Webmail';
|
|
||||||
|
|
||||||
// this key is used to encrypt the users imap password which is stored
|
|
||||||
// in the session record (and the client cookie if remember password is enabled).
|
|
||||||
// please provide a string of exactly 24 chars.
|
|
||||||
// YOUR KEY MUST BE DIFFERENT THAN THE SAMPLE VALUE FOR SECURITY REASONS
|
|
||||||
$config['des_key'] = 'sv5KuHfUagjggBU2KzXI2Uo';
|
|
||||||
// $config['des_key'] = 'Change_me_I_am_example!!';
|
|
||||||
|
|
||||||
// List of active plugins (in plugins/ directory)
|
|
||||||
$config['plugins'] = array(
|
|
||||||
'archive',
|
|
||||||
'zipdownload',
|
|
||||||
// 'managesieve',
|
|
||||||
// 'identity_smtp',
|
|
||||||
// 'carddav',
|
|
||||||
'newmail_notifier',
|
|
||||||
// 'html5_notifier',
|
|
||||||
);
|
|
||||||
|
|
||||||
// skin name: folder from skins/
|
|
||||||
// $config['skin'] = 'larry';
|
|
||||||
|
|
||||||
//$config['debug_level'] = 4;
|
|
||||||
//$config['imap_debug'] = true;
|
|
||||||
$config['imap_cache'] = 'db';
|
|
||||||
$config['messages_cache'] = true;
|
|
||||||
$config['ip_check'] = false;
|
|
Loading…
x
Reference in New Issue
Block a user