roundcube
This commit is contained in:
parent
32d81b73bb
commit
79f4015906
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
db
|
13
README.md
13
README.md
@ -1,3 +1,12 @@
|
||||
# docker-compose-workshop
|
||||
Update, run, inspect and stop server:
|
||||
```
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker-compose logs -t -f
|
||||
docker-compose down
|
||||
```
|
||||
Login to roundcube
|
||||
```
|
||||
docker-compose exec roundcube sh
|
||||
|
||||
Docker-Compose workshop
|
||||
```
|
||||
|
26
docker-compose.yaml
Normal file
26
docker-compose.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
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:
|
40
fpm.nginx.conf
Normal file
40
fpm.nginx.conf
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
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
Normal file
3
plugins/carddav/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
config.inc.php
|
||||
composer.phar
|
||||
/vendor
|
52
plugins/carddav/ChangeLog
Normal file
52
plugins/carddav/ChangeLog
Normal file
@ -0,0 +1,52 @@
|
||||
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
|
37
plugins/carddav/INSTALL
Normal file
37
plugins/carddav/INSTALL
Normal file
@ -0,0 +1,37 @@
|
||||
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'
|
5
plugins/carddav/INSTALLFROMGIT.md
Normal file
5
plugins/carddav/INSTALLFROMGIT.md
Normal file
@ -0,0 +1,5 @@
|
||||
- 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`
|
339
plugins/carddav/LICENSE
Normal file
339
plugins/carddav/LICENSE
Normal file
@ -0,0 +1,339 @@
|
||||
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.
|
47
plugins/carddav/README.md
Normal file
47
plugins/carddav/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
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/*`.
|
684
plugins/carddav/carddav.php
Normal file
684
plugins/carddav/carddav.php
Normal file
@ -0,0 +1,684 @@
|
||||
<?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
|
||||
);
|
||||
}}}
|
||||
|
||||
}
|
||||
|
||||
?>
|
2460
plugins/carddav/carddav_backend.php
Normal file
2460
plugins/carddav/carddav_backend.php
Normal file
File diff suppressed because it is too large
Load Diff
397
plugins/carddav/carddav_common.php
Normal file
397
plugins/carddav/carddav_common.php
Normal file
@ -0,0 +1,397 @@
|
||||
<?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);
|
||||
}}}
|
||||
}
|
||||
|
||||
?>
|
280
plugins/carddav/carddav_discovery.php
Normal file
280
plugins/carddav/carddav_discovery.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?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();
|
||||
|
||||
?>
|
38
plugins/carddav/composer.json
Normal file
38
plugins/carddav/composer.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"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
Normal file
136
plugins/carddav/composer.lock
generated
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"_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": []
|
||||
}
|
217
plugins/carddav/config.inc.php.dist
Normal file
217
plugins/carddav/config.inc.php.dist
Normal file
@ -0,0 +1,217 @@
|
||||
<?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,
|
||||
);
|
||||
*/
|
84
plugins/carddav/dbmigrations/0000-dbinit/mysql.sql
Normal file
84
plugins/carddav/dbmigrations/0000-dbinit/mysql.sql
Normal file
@ -0,0 +1,84 @@
|
||||
-- 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;
|
105
plugins/carddav/dbmigrations/0000-dbinit/postgres.sql
Normal file
105
plugins/carddav/dbmigrations/0000-dbinit/postgres.sql
Normal file
@ -0,0 +1,105 @@
|
||||
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)
|
||||
);
|
89
plugins/carddav/dbmigrations/0000-dbinit/sqlite3.sql
Normal file
89
plugins/carddav/dbmigrations/0000-dbinit/sqlite3.sql
Normal file
@ -0,0 +1,89 @@
|
||||
-- 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
plugins/carddav/dbmigrations/0000-sample/mysql.sql
Normal file
1
plugins/carddav/dbmigrations/0000-sample/mysql.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
1
plugins/carddav/dbmigrations/0000-sample/postgres.sql
Normal file
1
plugins/carddav/dbmigrations/0000-sample/postgres.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
1
plugins/carddav/dbmigrations/0000-sample/sqlite3.sql
Normal file
1
plugins/carddav/dbmigrations/0000-sample/sqlite3.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
1
plugins/carddav/dbmigrations/0001-categories/mysql.sql
Normal file
1
plugins/carddav/dbmigrations/0001-categories/mysql.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD `use_categories` INT NOT NULL DEFAULT '0' AFTER `presetname`;
|
@ -0,0 +1 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD COLUMN use_categories SMALLINT NOT NULL DEFAULT 0;
|
1
plugins/carddav/dbmigrations/0001-categories/sqlite3.sql
Normal file
1
plugins/carddav/dbmigrations/0001-categories/sqlite3.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ADD use_categories TINYINT NOT NULL DEFAULT 0;
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `username` VARCHAR(255);
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `presetname` VARCHAR(255);
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ALTER COLUMN username TYPE VARCHAR(255);
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks ALTER COLUMN presetname TYPE VARCHAR(255);
|
@ -0,0 +1,32 @@
|
||||
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;
|
@ -0,0 +1 @@
|
||||
This migration has been disabled because it was broken. It got fixed and replaced by 0004-fixtimestampdefaultvalue.
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- Just an example migration.
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
@ -0,0 +1 @@
|
||||
ALTER TABLE TABLE_PREFIXcarddav_addressbooks MODIFY COLUMN `last_updated` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:01';
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
@ -0,0 +1,56 @@
|
||||
-- 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;
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
@ -0,0 +1 @@
|
||||
SELECT * FROM TABLE_PREFIXcarddav_migrations; -- No migration
|
17
plugins/carddav/localization/cs_CZ.inc
Normal file
17
plugins/carddav/localization/cs_CZ.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
21
plugins/carddav/localization/de_DE.inc
Normal file
21
plugins/carddav/localization/de_DE.inc
Normal file
@ -0,0 +1,21 @@
|
||||
<?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_)',
|
||||
);
|
||||
?>
|
21
plugins/carddav/localization/en_US.inc
Normal file
21
plugins/carddav/localization/en_US.inc
Normal file
@ -0,0 +1,21 @@
|
||||
<?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_)',
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/es_ES.inc
Normal file
17
plugins/carddav/localization/es_ES.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
20
plugins/carddav/localization/fr_FR.inc
Normal file
20
plugins/carddav/localization/fr_FR.inc
Normal file
@ -0,0 +1,20 @@
|
||||
<?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é',
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/hu_HU.inc
Normal file
17
plugins/carddav/localization/hu_HU.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/id_ID.inc
Normal file
17
plugins/carddav/localization/id_ID.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/it_IT.inc
Normal file
17
plugins/carddav/localization/it_IT.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
18
plugins/carddav/localization/pl_PL.inc
Normal file
18
plugins/carddav/localization/pl_PL.inc
Normal file
@ -0,0 +1,18 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/ru_RU.inc
Normal file
17
plugins/carddav/localization/ru_RU.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/sv_SE.inc
Normal file
17
plugins/carddav/localization/sv_SE.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
17
plugins/carddav/localization/uk_UK.inc
Normal file
17
plugins/carddav/localization/uk_UK.inc
Normal file
@ -0,0 +1,17 @@
|
||||
<?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!",
|
||||
);
|
||||
?>
|
75
plugins/carddav/package.xml
Normal file
75
plugins/carddav/package.xml
Normal file
@ -0,0 +1,75 @@
|
||||
<?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>
|
6
plugins/carddav/skins/classic/carddav.css
Normal file
6
plugins/carddav/skins/classic/carddav.css
Normal file
@ -0,0 +1,6 @@
|
||||
#sections-table #rcmrowcd_preferences td.section {
|
||||
background-position: 6px -766px;
|
||||
}
|
||||
#sections-table #rcmrowcd_preferences.selected td.section {
|
||||
background-position: 6px -791px;
|
||||
}
|
3
plugins/carddav/skins/elastic/carddav.css
Normal file
3
plugins/carddav/skins/elastic/carddav.css
Normal file
@ -0,0 +1,3 @@
|
||||
.listing.iconized tr.cd_preferences>td.section:before {
|
||||
content: "\f47f"
|
||||
}
|
6
plugins/carddav/skins/larry/carddav.css
Normal file
6
plugins/carddav/skins/larry/carddav.css
Normal file
@ -0,0 +1,6 @@
|
||||
#sections-table #rcmrowcd_preferences td.section {
|
||||
background-position: 6px -766px;
|
||||
}
|
||||
#sections-table #rcmrowcd_preferences.selected td.section {
|
||||
background-position: 6px -791px;
|
||||
}
|
110
plugins/managesieve/config.inc.php
Normal file
110
plugins/managesieve/config.inc.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?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;
|
101
roundcube.config.php
Normal file
101
roundcube.config.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?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