├── .htaccess ├── CONTRIBUTING.md ├── COPYING ├── README.md ├── admin ├── index.php └── setup.php ├── cdavurls.php ├── class ├── CalDAVDolibarr.php ├── CardDAVDolibarr.php ├── PrincipalsDolibarr.php └── actions_cdav.class.php ├── core └── modules │ └── modCDav.class.php ├── doc ├── description_en.html ├── description_fr.html ├── description_lo_en.html ├── description_lo_fr.html ├── documentation_lo_en.odt ├── documentation_lo_en.pdf ├── logo_cdav_fil.png ├── logo_cdav_v2.png ├── long-description_en.html ├── long-description_fr.html ├── long-description_lo_en.html └── long-description_lo_fr.html ├── ics.php ├── img └── object_cdav.png ├── index.php ├── langs ├── en_US │ └── cdav.lang └── fr_FR │ └── cdav.lang ├── lib └── cdav.lib.php ├── server.php └── sql ├── llx_actioncomm_cdav.sql └── update_001.sql /.htaccess: -------------------------------------------------------------------------------- 1 | ## HTTP Auth workaround for php in fastcgi mode 2 | SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 3 | 4 | 5 | RewriteEngine on 6 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 7 | 8 | # for Apache 2.4.13 or later 9 | = 2.4.13> 10 | CGIPassAuth on 11 | 12 | 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to contribute to Befox/cdav 2 | 3 | ============================= 4 | 5 | Bug reports and feature requests 6 | -------------------------------- 7 | 8 | *Note*: Issues are not a support forum. If you need help using the software, please use [the forums](http://www.dolibarr.org/forum). 9 | 10 | Issues are managed on [GitHub](https://github.com/Befox/cdav/issues). 11 | 12 | 1. Please [use the search engine](https://help.github.com/articles/searching-issues) to check if nobody's already reported your problem. 13 | 2. [Create an issue](https://help.github.com/articles/creating-an-issue). Choose an appropriate title. Prepend appropriately with Bug or Feature Request. 14 | 4. Tell us the version you are using! 15 | 3. Write a report with as much detail as possible (Use [screenshots](https://help.github.com/articles/issue-attachments) or even screencasts and provide logging and debugging informations whenever possible). 16 | 17 | 18 | 19 | Code 20 | --------------------- 21 | 22 | ### Resources 23 | [Developer documentation](http://wiki.dolibarr.org/index.php/Developer_documentation) 24 | 25 | Translations 26 | ------------ 27 | The source language (en_US) is maintained in the repository. See the [Code](#code) section above. 28 | 29 | 30 | Note: Sometimes, the source text (english) is modified. In such a case, the translation is reset. Transifex assume that if the original source 31 | has changed, the translation is surely no more correct so must be done again. But old translation is not lost and you can use the tab "History" 32 | to retreive all old translation of a source text, and restore the translation in one click with no need to retranslate it if there is no need to. 33 | 34 | 35 | ### Resources 36 | [Translator documentation](http://wiki.dolibarr.org/index.php/Translator_documentation) 37 | 38 | Documentation 39 | ------------- 40 | The project's documentation is maintained on the [Wiki](http://wiki.dolibarr.org/index.php). 41 | 42 | *Note*: to help prevent spam, you need to create an account before being able to edit. Everybody is welcome to contribute to its content. 43 | 44 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CDav module for Dolibarr 2 | 3 | ## What is it ? 4 | 5 | This module for Dolibarr 16.0/18.0 adds CardDAV / CalDAV and ICS synchronisation. It uses Dolibarr [Sabre/DAV](http://sabre.io/dav/) server library. 6 | 7 | You can : 8 | 9 | * Read and edit calendars through CalDAV 10 | * Read and edit project tasks through CalDAV 11 | * Read and edit address books through CardDAV 12 | * Read calendars through ICS Full version or only Free/Busy (hide details) 13 | * Access Dolibarr documents through WebDAV (if admin) 14 | * Generate project tasks from documents like proposals and/or orders 15 | 16 | Each user can access his/her contacts and thirdparties address books (public and own private contacts), his/her own calendar and other users calendars according to his/her rights. 17 | 18 | Dolibarr contact informations fill personnal informations in client software cards (including contact photo). 19 | 20 | Society (thirdparty) informations (to which contact is attached) fill professional informations in client software cards. 21 | 22 | Three adress books are proposed to sync : Contacts, Thirdparties and Members. If you want to modify a thirdparty infomation, do it in thirdparties address book. 23 | 24 | It is possible to select which contacts to sync with CDAV_CONTACT_TAG configuration value in Home / Setup / Other setup. Enter a contact tag value and then only contacts with this tag will be synced (empty value for all). 25 | 26 | Calendar records with "Status / Percentage" set to "Not applicable" are converted to events in CalDAV (VEVENT), others are converted to tasks (VTODO). 27 | 28 | Recurring events are not handled (Dolibarr does not handle them). 29 | 30 | Automatic tasks generation in projects with services from linked Propositions and/or Orders 31 | Module setup offer you to : 32 | 33 | * generate tasks from linked docuement(s) OR not 34 | * synchronize project tasks as calendar events AND/OR todo tasks 35 | * set up 3 initial tasks that will appear before services coming from document(s) 36 | * set up 3 final tasks that will appear after services coming from document(s) 37 | * define user role in project to select user to attribute on generated tasks from document(s) 38 | * define user role on new project task creation 39 | * define start and end time of a working day 40 | * restrict services to be converted as task by specifying a tag 41 | * force generation of tasks for each service lines from attached documents with cdav duration if tag is missing 42 | 43 | Durations are retrieved from service's card if defined (minutes, hours, days or weeks only), otherwise from extrafield filled in documents 44 | All tasks are begining at the starting date of the project, at the begining of the working day 45 | Multi-day durations tasks are maintained as a single task, eg from 31/07/2018 at 8am to 02/08/2018 at 7pm 46 | 47 | Usage : 48 | 49 | * Manually create a project, link it to a third party, and set up the date ; leave it in draft status 50 | * Attach document(s) : proposals or orders including at least 1 concerned service. 51 | * Affect contact(s) with correct role 52 | * Validate project : all tasks are created ; use your ics client software to retrieve and drag-drop events if necessary 53 | 54 | Notes : 55 | 56 | * Description of services are useful to create subtasks if '- ' are detected at the begining of a line ; then, with DAVx⁵ (CalDAV/CardDAV Synchronization and Client) and Tasks (Keep track of your list of goals) you will be able to use checkboxes for these tasks 57 | * If you chose to synchronize project tasks as calendar events AND todo tasks, modifying a task will autoamticaly modify the corresponding event and reciprocally. 58 | * Tasks can be modified from client application but not cancelled : Dolibarr keep trace of last affectation 59 | * After generating tasks, you can modify/complete each of them or create more tasks manually (here too you can fill description zone with '- ' at the begining of lines to create subtasks) 60 | 61 | 62 | ## Help improvements 63 | 64 | If you find the module is useful and want to finance improvements, consider to pay it on [Dolistore](https://www.dolistore.com/fr/modules/526-Synchronisation-CardDAV---CalDAV---ICS.html) 65 | 66 | ## How to install 67 | 68 | PHP 8.0+ is required. 69 | 70 | Dolibarr native calendar module must be activated *before* installing CDav module. 71 | 72 | * Clone repository _git clone https://github.com/Befox/cdav.git_ and install cdav directory in dolibarr/htdocs/ 73 | * Or unzip [last release](https://github.com/Befox/cdav/archive/master.zip), rename _cdav-master_ to _cdav_ and copy it into dolibarr/htdocs/ 74 | 75 | Enable CDav module in Interfaces Modules list. 76 | 77 | It would add a link in Agenda left menu and in Contacts left menu to access DAV / ICS URLs. 78 | 79 | Use these URLs in your CardDAV or CalDAV client software. 80 | 81 | ## How to upgrade 82 | 83 | * Disable CDav module in Interfaces Modules list. 84 | * Unzip last version or _git pull_ in dolibarr/htdocs/cdav 85 | * Enable CDav module in Modules list. 86 | 87 | 88 | ## DAV URLs 89 | 90 | ### Thunderbird 91 | 92 | [Thunderbird](https://www.thunderbird.net) (with [Lightning](https://addons.mozilla.org/thunderbird/addon/lightning/), [TBSync](https://addons.thunderbird.net/thunderbird/addon/tbsync/) and its [Provider for CalDAV/CardDAV](https://addons.thunderbird.net/thunderbird/addon/dav-4-tbsync/) addons) needs a precise URL for each address book and calendar : 93 | 94 | https://server.example.com/dolibarr/htdocs/cdav/server.php/calendars//-cal- 95 | 96 | https://server.example.com/dolibarr/htdocs/cdav/server.php/addressbooks//default/ 97 | 98 | ### DAVx⁵ 99 | 100 | [DAVx⁵](https://www.davx5.com/) can detect automatically address book and all existing calendars (if an event exists) with generic DAV URL : 101 | 102 | https://server.example.com/dolibarr/htdocs/cdav/server.php 103 | 104 | You can use a tasks application to manage Dolibarr tasks (VTODO) on Android. DAVx⁵ is compatible with [OpenTasks](https://github.com/dmfs/opentasks). 105 | 106 | In CDav configuration, you can activate a QRCode display to autoconfigure DAVx⁵. 107 | 108 | Be carefull, if you use https, DAVx⁵ needs a valid SSL certificate, excluding auto-signed certificates. 109 | 110 | DAVx⁵ is also available on [F-Droid](https://f-droid.org/packages/at.bitfire.davdroid/). 111 | 112 | ### iOS 113 | 114 | iOS uses _principals_ url to grab list of CalDAV or CardDAV resources : 115 | 116 | https://server.example.com/dolibarr/htdocs/cdav/server.php/principals/ 117 | 118 | ### WebDAV 119 | 120 | Admin users can also access Dolibarr documents through WebDAV with WebDAV URL : 121 | 122 | https://server.example.com/dolibarr/htdocs/cdav/server.php/documents/ 123 | 124 | ## Troubleshooting 125 | 126 | To test cdav module, you can use DAVx⁵ url https://server.example.com/dolibarr/htdocs/cdav/ in a web browser. Error messages are clearer. 127 | 128 | ### Apache web server 129 | 130 | Apache *rewrite* module is necessary if you use fcgi or php-fpm mode. In this case, .htacess file in cdav module has to be read by Apache or reported in your Apache configuration. 131 | 132 | SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 133 | 134 | or 135 | 136 | 137 | 138 | RewriteEngine on 139 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 140 | 141 | 142 | 143 | or (this is usefull on Plesk when nginx is proxying Apache) 144 | 145 | FcgidPassHeader AUTHORIZATION 146 | 147 | It is recommanded to *disable* these Apache modules : *dav* / *dav_fs* / *dav_lock* 148 | 149 | ### nginx web server 150 | 151 | To solve authentication loop, add these directives to your nginx "location" rubrique : 152 | 153 | fastcgi_param PHP_AUTH_USER $remote_user; 154 | fastcgi_param PHP_AUTH_PW $http_authorization; 155 | 156 | or 157 | 158 | fastcgi_pass_header Authorization; 159 | 160 | ### nginx reverse proxy 161 | 162 | To solve authentication loop, add this directive to your nginx "location" rubrique : 163 | 164 | proxy_pass_header Authorization; 165 | 166 | 167 | -------------------------------------------------------------------------------- /admin/index.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/admin/index.php -------------------------------------------------------------------------------- /admin/setup.php: -------------------------------------------------------------------------------- 1 | load("admin"); 36 | $langs->load("other"); 37 | $langs->load("cdav@cdav"); 38 | 39 | // Security check 40 | if (! $user->admin || !empty($user->design)) accessforbidden(); 41 | 42 | $action = GETPOST('action', 'alpha'); 43 | 44 | $taskcontact_types=array(); 45 | $sql = 'SELECT rowid, libelle FROM '.MAIN_DB_PREFIX.'c_type_contact WHERE element="project_task" AND source="internal" AND active=1'; 46 | $result = $db->query($sql); 47 | if ($result!==false) 48 | { 49 | while(($row=$db->fetch_object($result))!==null) 50 | $taskcontact_types[$row->rowid] = $row->libelle; 51 | } 52 | $projcontact_types=array(); 53 | $sql = 'SELECT rowid, libelle FROM '.MAIN_DB_PREFIX.'c_type_contact WHERE element="project" AND source="internal" AND active=1'; 54 | $result = $db->query($sql); 55 | if ($result!==false) 56 | { 57 | while(($row=$db->fetch_object($result))!==null) 58 | $projcontact_types[$row->rowid] = $row->libelle; 59 | } 60 | 61 | $tasksync_method=array( 62 | '0' => $langs->trans("Not synchonized"), 63 | '1' => $langs->trans("Sync as calendar events only"), 64 | '2' => $langs->trans("Sync as todo tasks only"), 65 | '3' => $langs->trans("Sync as calendar events and todo tasks"), 66 | ); 67 | 68 | $thirdsync_method=array( 69 | '0' => $langs->trans("Not synchonized"), 70 | '1' => $langs->trans("Only thirdparties without contact"), 71 | '2' => $langs->trans("All thirdparties"), 72 | ); 73 | 74 | $form = new Form($db); 75 | /* 76 | * Actions 77 | */ 78 | 79 | if ($action == 'setvalue') { 80 | // save the setting 81 | 82 | $valCDAV_URI_KEY = substr(GETPOST('CDAV_URI_KEY', 'alphanohtml'),0,8); 83 | if($valCDAV_URI_KEY=='') 84 | $valCDAV_URI_KEY = substr(md5(time()),0,8); 85 | 86 | dolibarr_set_const( 87 | $db, "CDAV_URI_KEY", 88 | $valCDAV_URI_KEY, 'chaine', 0, '', $conf->entity 89 | ); 90 | dolibarr_set_const( 91 | $db, "CDAV_CONTACT_TAG", 92 | GETPOST('CDAV_CONTACT_TAG', 'alphanohtml'), 'chaine', 0, '', $conf->entity 93 | ); 94 | dolibarr_set_const( 95 | $db, "CDAV_THIRD_SYNC", 96 | GETPOST('CDAV_THIRD_SYNC', 'alphanohtml'), 'chaine', 0, '', $conf->entity 97 | ); 98 | dolibarr_set_const( 99 | $db, "CDAV_MEMBER_SYNC", 100 | GETPOST('CDAV_MEMBER_SYNC', 'alphanohtml'), 'chaine', 0, '', $conf->entity 101 | ); 102 | dolibarr_set_const( 103 | $db, "CDAV_SYNC_PAST", 104 | GETPOST('CDAV_SYNC_PAST', 'alphanohtml'), 'chaine', 0, '', $conf->entity 105 | ); 106 | dolibarr_set_const( 107 | $db, "CDAV_SYNC_FUTURE", 108 | GETPOST('CDAV_SYNC_FUTURE', 'alphanohtml'), 'chaine', 0, '', $conf->entity 109 | ); 110 | dolibarr_set_const( 111 | $db, "CDAV_TASK_SYNC", 112 | GETPOST('CDAV_TASK_SYNC', 'alphanohtml'), 'chaine', 0, '', $conf->entity 113 | ); 114 | dolibarr_set_const( 115 | $db, "CDAV_TASK_USER_ROLE", 116 | GETPOST('CDAV_TASK_USER_ROLE', 'alphanohtml'), 'chaine', 0, '', $conf->entity 117 | ); 118 | dolibarr_set_const( 119 | $db, "CDAV_GENTASK", 120 | GETPOST('CDAV_GENTASK', 'alphanohtml'), 'chaine', 0, '', $conf->entity 121 | ); 122 | dolibarr_set_const( 123 | $db, "CDAV_GENTASK_INI1", 124 | GETPOST('CDAV_GENTASK_INI1', 'alphanohtml'), 'chaine', 0, '', $conf->entity 125 | ); 126 | dolibarr_set_const( 127 | $db, "CDAV_GENTASK_INI2", 128 | GETPOST('CDAV_GENTASK_INI2', 'alphanohtml'), 'chaine', 0, '', $conf->entity 129 | ); 130 | dolibarr_set_const( 131 | $db, "CDAV_GENTASK_INI3", 132 | GETPOST('CDAV_GENTASK_INI3', 'alphanohtml'), 'chaine', 0, '', $conf->entity 133 | ); 134 | dolibarr_set_const( 135 | $db, "CDAV_GENTASK_END1", 136 | GETPOST('CDAV_GENTASK_END1', 'alphanohtml'), 'chaine', 0, '', $conf->entity 137 | ); 138 | dolibarr_set_const( 139 | $db, "CDAV_GENTASK_END2", 140 | GETPOST('CDAV_GENTASK_END2', 'alphanohtml'), 'chaine', 0, '', $conf->entity 141 | ); 142 | dolibarr_set_const( 143 | $db, "CDAV_GENTASK_END3", 144 | GETPOST('CDAV_GENTASK_END3', 'alphanohtml'), 'chaine', 0, '', $conf->entity 145 | ); 146 | dolibarr_set_const( 147 | $db, "CDAV_PROJ_USER_ROLE", 148 | GETPOST('CDAV_PROJ_USER_ROLE', 'alphanohtml'), 'chaine', 0, '', $conf->entity 149 | ); 150 | dolibarr_set_const( 151 | $db, "CDAV_GENTASK_SERVICE_TAG", 152 | GETPOST('CDAV_GENTASK_SERVICE_TAG', 'alphanohtml'), 'chaine', 0, '', $conf->entity 153 | ); 154 | dolibarr_set_const( 155 | $db, "CDAV_EXTRAFIELD_DURATION", 156 | GETPOST('CDAV_EXTRAFIELD_DURATION', 'alphanohtml'), 'chaine', 0, '', $conf->entity 157 | ); 158 | dolibarr_set_const( 159 | $db, "CDAV_TASK_HOUR_INI", 160 | GETPOST('CDAV_TASK_HOUR_INI', 'alphanohtml'), 'chaine', 0, '', $conf->entity 161 | ); 162 | dolibarr_set_const( 163 | $db, "CDAV_TASK_HOUR_END", 164 | GETPOST('CDAV_TASK_HOUR_END', 'alphanohtml'), 'chaine', 0, '', $conf->entity 165 | ); 166 | dolibarr_set_const( 167 | $db, "CDAV_QRCODE_DAVX5_ENABLED", 168 | GETPOST('CDAV_QRCODE_DAVX5_ENABLED', 'alphanohtml'), 'chaine', 0, '', $conf->entity 169 | ); 170 | 171 | 172 | $mesg = "".$langs->trans("SetupSaved").""; 173 | } 174 | 175 | /* 176 | * View 177 | */ 178 | 179 | $page_name = $langs->trans("CDav Setup") . " - " . $langs->trans("CDav General Setting"); 180 | llxHeader('', $page_name); 181 | 182 | $linkback=''.$langs->trans("BackToModuleList").''; 183 | print_fiche_titre($page_name, $linkback, 'title_setup'); 184 | 185 | $CDAV_URI_KEY=substr($conf->global->CDAV_URI_KEY,0,8); 186 | $CDAV_CONTACT_TAG=$conf->global->CDAV_CONTACT_TAG; 187 | $CDAV_THIRD_SYNC=$conf->global->CDAV_THIRD_SYNC; 188 | $CDAV_MEMBER_SYNC=$conf->global->CDAV_MEMBER_SYNC; 189 | $CDAV_SYNC_PAST=$conf->global->CDAV_SYNC_PAST; 190 | $CDAV_SYNC_FUTURE=$conf->global->CDAV_SYNC_FUTURE; 191 | $CDAV_TASK_SYNC=$conf->global->CDAV_TASK_SYNC; 192 | $CDAV_TASK_USER_ROLE=$conf->global->CDAV_TASK_USER_ROLE; 193 | $CDAV_GENTASK=$conf->global->CDAV_GENTASK; 194 | $CDAV_GENTASK_INI1=$conf->global->CDAV_GENTASK_INI1; 195 | $CDAV_GENTASK_INI2=$conf->global->CDAV_GENTASK_INI2; 196 | $CDAV_GENTASK_INI3=$conf->global->CDAV_GENTASK_INI3; 197 | $CDAV_GENTASK_END1=$conf->global->CDAV_GENTASK_END1; 198 | $CDAV_GENTASK_END2=$conf->global->CDAV_GENTASK_END2; 199 | $CDAV_GENTASK_END3=$conf->global->CDAV_GENTASK_END3; 200 | $CDAV_PROJ_USER_ROLE=$conf->global->CDAV_PROJ_USER_ROLE; 201 | $CDAV_GENTASK_SERVICE_TAG=$conf->global->CDAV_GENTASK_SERVICE_TAG; 202 | $CDAV_EXTRAFIELD_DURATION=$conf->global->CDAV_EXTRAFIELD_DURATION; 203 | $CDAV_TASK_HOUR_INI=$conf->global->CDAV_TASK_HOUR_INI; 204 | $CDAV_TASK_HOUR_END=$conf->global->CDAV_TASK_HOUR_END; 205 | $CDAV_QRCODE_DAVX5_ENABLED=$conf->global->CDAV_QRCODE_DAVX5_ENABLED; 206 | 207 | 208 | dol_fiche_head('', 'setup', $langs->trans("CDav"), 0, "cdav@cdav"); 209 | 210 | print_titre($langs->trans("CDav Setting Value")); 211 | print '
'; 212 | print '
'; 213 | print ''; 214 | print ''; 215 | print ''; 216 | print ''; 217 | print ''; 218 | print ''; 219 | print ''."\n"; 220 | 221 | print ''; 222 | print ''; 223 | print ''."\n"; 226 | 227 | print ''; 228 | print ''; 229 | print ''."\n"; 232 | 233 | print ''; 234 | print ''; 235 | print ''."\n"; 238 | 239 | print ''; 240 | print ''; 241 | print ''."\n"; 244 | 245 | print ''; 246 | print ''; 247 | print ''."\n"; 252 | 253 | print ''; 254 | print ''; 255 | print ''."\n"; 256 | 257 | print ''; 258 | print ''; 259 | print ''."\n"; 262 | 263 | print ''; 264 | print ''; 265 | print ''."\n"; 268 | 269 | print ''; 270 | print ''; 271 | print ''."\n"; 278 | 279 | print ''; 280 | print ''; 281 | print ''."\n"; 288 | 289 | print ''; 290 | print ''; 291 | print ''."\n"; 294 | 295 | print ''; 296 | print ''; 297 | print ''."\n"; 300 | 301 | print ''; 302 | print ''; 303 | print ''."\n"; 308 | 309 | print ''; 310 | print ''; 311 | print ''."\n"; 314 | 315 | print ''; 316 | print ''; 317 | print ''."\n"; 320 | 321 | print ''; 322 | print ''; 323 | print ''."\n"; 326 | 327 | // Boutons d'action 328 | print ''."\n"; 333 | print '
'.$langs->trans("desc").''.$langs->trans("value").'
'.$langs->trans("Sync token").'
'.$langs->trans("Change it to force client to resync").'
'; 224 | print ''; 225 | print '
'.$langs->trans("Contacts filter").'
'.$langs->trans("Contact tag to restrict contacts to sync, leave blank to sync all").'
'; 230 | print $form->select_all_categories("contact", $CDAV_CONTACT_TAG, 'CDAV_CONTACT_TAG', 0); 231 | print '
'.$langs->trans("Enable thirdparties sync").'
'.$langs->trans("How to synchronize thirparties").'
'; 236 | print $form->selectarray('CDAV_THIRD_SYNC', $thirdsync_method, $CDAV_THIRD_SYNC); 237 | print '
'.$langs->trans("EnableMembersSync").'
'.$langs->trans("GenerateAddressbookForMembership").'
'; 242 | print $form->selectyesno('CDAV_MEMBER_SYNC', $CDAV_MEMBER_SYNC, 1); 243 | print '
'.$langs->trans("Period to sync").'
'.$langs->trans("Number of days to sync before and after today").'
'; 248 | print $langs->trans("In past:").' '.$langs->trans("days"); 249 | print '
'; 250 | print $langs->trans("In future:").' '.$langs->trans("days"); 251 | print '
'.$langs->trans("Project tasks synchronization").'
'.$langs->trans("Enable project tasks sync").'
'.$langs->trans("How to synchronize project tasks").'
'; 260 | print $form->selectarray('CDAV_TASK_SYNC', $tasksync_method, $CDAV_TASK_SYNC); 261 | print '
'.$langs->trans("Generate tasks from documents").'
'.$langs->trans("Generate project tasks for each service lines from attached documents (proposals or orders) on project validation. Only the lastest documents are used in case of inheritance").'
'; 266 | print $form->selectyesno('CDAV_GENTASK', $CDAV_GENTASK, 1); 267 | print '
'.$langs->trans("Generate initial tasks from services").'
'.$langs->trans("Generate project initial tasks for each seleted services on project validation.").'
'; 272 | print $form->select_produits($CDAV_GENTASK_INI1, 'CDAV_GENTASK_INI1', 1); 273 | print '
'; 274 | print $form->select_produits($CDAV_GENTASK_INI2, 'CDAV_GENTASK_INI2', 1); 275 | print '
'; 276 | print $form->select_produits($CDAV_GENTASK_INI3, 'CDAV_GENTASK_INI3', 1); 277 | print '
'.$langs->trans("Generate final tasks from services").'
'.$langs->trans("Generate project final tasks for each seleted services on project validation.").'
'; 282 | print $form->select_produits($CDAV_GENTASK_END1, 'CDAV_GENTASK_END1', 1); 283 | print '
'; 284 | print $form->select_produits($CDAV_GENTASK_END2, 'CDAV_GENTASK_END2', 1); 285 | print '
'; 286 | print $form->select_produits($CDAV_GENTASK_END3, 'CDAV_GENTASK_END3', 1); 287 | print '
'.$langs->trans("Project user role").'
'.$langs->trans("User role in project to select user to attribute on generated tasks from documents").'
'; 292 | print $form->selectarray('CDAV_PROJ_USER_ROLE', $projcontact_types, $CDAV_PROJ_USER_ROLE); 293 | print '
'.$langs->trans("Project task user role").'
'.$langs->trans("User role on new project task creation").'
'; 298 | print $form->selectarray('CDAV_TASK_USER_ROLE', $taskcontact_types, $CDAV_TASK_USER_ROLE); 299 | print '
'.$langs->trans("Project task working hours").'
'.$langs->trans("Start and end time of a working day").'
'; 304 | print $langs->trans("Begining at:").' '.$langs->trans("hour"); 305 | print '
'; 306 | print $langs->trans("Ending at:").' '.$langs->trans("hour"); 307 | print '
'.$langs->trans("Services filter TAG").'
'.$langs->trans("Service tag to restrict services to be converted as task, leave blank to sync all").'
'; 312 | print $form->select_all_categories("product", $CDAV_GENTASK_SERVICE_TAG, 'CDAV_GENTASK_SERVICE_TAG', 0); 313 | print '
'.$langs->trans("Service duration from documents").'
'.$langs->trans("Generate project tasks for each service lines from attached documents with cdav duration, even if TAG is missing").'
'; 318 | print $form->selectyesno('CDAV_EXTRAFIELD_DURATION', $CDAV_EXTRAFIELD_DURATION, 1); 319 | print '
'.$langs->trans("ActivateDavX5autoURL").'
'.$langs->trans("ActivateDavX5autoURLTooltip").'
'; 324 | print $form->selectyesno('CDAV_QRCODE_DAVX5_ENABLED', $CDAV_QRCODE_DAVX5_ENABLED, 1); 325 | print '
'; 329 | print '
'; 330 | print ''; 331 | print '
'; 332 | print '
'; 334 | print '
'; 335 | // Show errors 336 | print "
"; 337 | 338 | if(!empty($object)) { // Fix Warning: Attempt to read property "error" on null : Is $object really used on this page? 339 | dol_htmloutput_errors($object->error, $object->errors); 340 | // Show messages 341 | dol_htmloutput_mesg($object->mesg, '', 'ok'); 342 | } 343 | 344 | // Footer 345 | llxFooter(); 346 | $db->close(); 347 | -------------------------------------------------------------------------------- /cdavurls.php: -------------------------------------------------------------------------------- 1 | 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } 31 | if (!$res && $i > 0 && @file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; 32 | if (!$res && $i > 0 && @file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; 33 | // Try main.inc.php using relative path 34 | if (!$res && @file_exists("../main.inc.php")) $res = @include "../main.inc.php"; 35 | if (!$res && @file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; 36 | if (!$res && @file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; 37 | if (!$res) die("Include of main fails"); 38 | 39 | require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; 40 | require_once DOL_DOCUMENT_ROOT.'/core/lib/barcode.lib.php'; // This is to include def like $genbarcode_loc and $font_loc 41 | 42 | function base64url_encode($data) { 43 | return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 44 | } 45 | 46 | // Load traductions files requiredby by page 47 | $langs->load("cdav"); 48 | 49 | 50 | // define CDAV_URI_KEY if not 51 | if(!defined('CDAV_URI_KEY')) 52 | { 53 | if(isset($conf->global->CDAV_URI_KEY)) 54 | define('CDAV_URI_KEY', $conf->global->CDAV_URI_KEY); 55 | else 56 | define('CDAV_URI_KEY', substr(md5($_SERVER['HTTP_HOST']),0,8)); 57 | } 58 | 59 | // Get parameters 60 | $id = GETPOST('id','int'); 61 | $action = GETPOST('action','alpha'); 62 | $backtopage = GETPOST('backtopage'); 63 | $type = GETPOST('type','alpha'); 64 | 65 | // Protection if external user 66 | if (!empty($user->societe_id) || !empty($user->socid)) // external user 67 | { 68 | accessforbidden(); 69 | } 70 | 71 | /*************************************************** 72 | * VIEW 73 | * 74 | * Put here all code to build page 75 | ****************************************************/ 76 | 77 | llxHeader('',$langs->trans($type.'url'),''); 78 | 79 | echo '

'.$langs->trans($type.'url').'

'; 80 | 81 | if(!empty($conf->global->CDAV_QRCODE_DAVX5_ENABLED)) { 82 | echo '

'.$langs->trans('URLForDavX5').'

'; 83 | echo '

'.$langs->trans('URLForDavX5Tooltip').'

'; 84 | 85 | require_once DOL_DOCUMENT_ROOT.'/core/modules/barcode/doc/tcpdfbarcode.modules.php'; 86 | $qrmodule = new modTcpdfbarcode(); 87 | $tcpdfEncoding = $qrmodule->getTcpdfEncodingType('QRCODE'); 88 | require_once TCPDF_PATH.'tcpdf_barcodes_2d.php'; 89 | $davx = "davx5://" . $user->login . ":@"; 90 | $uri = str_replace(["http://", "https://"],[$davx, $davx],dol_buildpath('cdav', 2)); 91 | $barcodeobj = new TCPDF2DBarcode($uri, $tcpdfEncoding); 92 | $qrdata = $barcodeobj->getBarcodePngData(); 93 | print "
"; 94 | } 95 | 96 | if($type=='CardDAV') 97 | { 98 | echo '

'.$langs->trans('URLGeneric').'

'; 99 | echo '
';
100 | 	echo dol_buildpath('cdav', 2)."\n";
101 | 	echo dol_buildpath('cdav/server.php', 2)."\n";
102 | 	echo dol_buildpath('cdav', 2)."/server.php/principals/".$user->login."/";
103 | 	echo '
'; 104 | 105 | echo '

'.$langs->trans('URLforCardDAV', 2).'

'; 106 | echo '
'.dol_buildpath('cdav/server.php', 2).'/addressbooks/'.$user->login.'/default/
'; 107 | } 108 | elseif($type=='CalDAV') 109 | { 110 | echo '

'.$langs->trans('URLGeneric').'

'; 111 | echo '
';
112 | 	echo dol_buildpath('cdav', 2)."\n";
113 | 	echo dol_buildpath('cdav/server.php', 2)."\n";
114 | 	echo dol_buildpath('cdav', 2)."/server.php/principals/".$user->login."/";
115 | 	echo '
'; 116 | 117 | echo '

'.$langs->trans('URLforCalDAV').'

'; 118 | 119 | if(isset($user->rights->agenda->allactions->read) && $user->rights->agenda->allactions->read) 120 | { 121 | if (versioncompare(versiondolibarrarray(), array(3,7,9))>0) 122 | $fk_soc_fieldname = 'fk_soc'; 123 | else 124 | $fk_soc_fieldname = 'fk_societe'; 125 | 126 | $sql = 'SELECT u.rowid, u.login, u.firstname, u.lastname 127 | FROM '.MAIN_DB_PREFIX.'user u WHERE '.$fk_soc_fieldname.' IS NULL 128 | AND u.fk_soc IS NULL AND u.statut = 1 129 | ORDER BY login'; 130 | $result = $db->query($sql); 131 | while($row = $db->fetch_array($result)) 132 | { 133 | if($row['rowid'] == $user->id) 134 | echo ''; 135 | echo $row['firstname'].' '.$row['lastname'].' :'; 136 | echo '
'.dol_buildpath('cdav/server.php', 2).'/calendars/'.$user->login.'/'.$row['rowid'].'-cal-'.$row['login'].'

'; 137 | if($row['rowid'] == $user->id) 138 | echo '
'; 139 | } 140 | } 141 | else 142 | { 143 | echo '
'.dol_buildpath('cdav/server.php', 2).'/calendars/'.$user->login.'/'.$user->id.'-cal-'.$user->login.'
'; 144 | } 145 | 146 | } 147 | elseif($type=='ICS') 148 | { 149 | 150 | echo '

'.$langs->trans('URLforICS').'

'; 151 | 152 | if(isset($user->rights->agenda->allactions->read) && $user->rights->agenda->allactions->read) 153 | { 154 | if (versioncompare(versiondolibarrarray(), array(3,7,9))>0) 155 | $fk_soc_fieldname = 'fk_soc'; 156 | else 157 | $fk_soc_fieldname = 'fk_societe'; 158 | 159 | $sql = 'SELECT u.rowid, u.login, u.firstname, u.lastname 160 | FROM '.MAIN_DB_PREFIX.'user u WHERE '.$fk_soc_fieldname.' IS NULL 161 | AND u.fk_soc IS NULL AND u.statut = 1 162 | ORDER BY login'; 163 | $result = $db->query($sql); 164 | while($row = $db->fetch_array($result)) 165 | { 166 | echo '

'.$row['firstname'].' '.$row['lastname'].' :

'; 167 | 168 | echo "
".$langs->trans('Full')." :\n".dol_buildpath('cdav/ics.php', 2).'?token='.base64url_encode(openssl_encrypt($row['rowid'].'+ø+full', 'aes-256-cbc', CDAV_URI_KEY, true))."\n\n";
169 | 			echo $langs->trans('NoLabel')." :\n".dol_buildpath('cdav/ics.php', 2).'?token='.base64url_encode(openssl_encrypt($row['rowid'].'+ø+nolabel', 'aes-256-cbc', CDAV_URI_KEY, true)).'

'; 170 | 171 | } 172 | } 173 | else 174 | { 175 | echo "
".$langs->trans('Full')." :\n".dol_buildpath('cdav/ics.php', 2).'?token='.base64url_encode(openssl_encrypt($user->id.'+ø+full', 'aes-256-cbc', CDAV_URI_KEY, true))."\n\n";
176 | 		echo $langs->trans('NoLabel')." :\n".dol_buildpath('cdav/ics.php', 2).'?token='.base64url_encode(openssl_encrypt($user->id.'+ø+nolabel', 'aes-256-cbc', CDAV_URI_KEY, true)).'

'; 177 | } 178 | 179 | } 180 | else 181 | { 182 | echo '

'.$langs->trans('URLGeneric').'

'; 183 | echo '
'.dol_buildpath('cdav', 2).'
'; 184 | } 185 | 186 | // End of page 187 | llxFooter(); 188 | $db->close(); 189 | -------------------------------------------------------------------------------- /class/PrincipalsDolibarr.php: -------------------------------------------------------------------------------- 1 | [ 54 | 'dbField' => 'displayname', 55 | ], 56 | 57 | /** 58 | * This is the users' primary email-address. 59 | */ 60 | '{http://sabredav.org/ns}email-address' => [ 61 | 'dbField' => 'email', 62 | ], 63 | ]; 64 | 65 | /** 66 | * Sets up the backend. 67 | * 68 | * @param db $db 69 | */ 70 | function __construct($user,$db) { 71 | 72 | $this->user = $user; 73 | $this->db = $db; 74 | 75 | $this->allprincipals = array( 76 | array('id'=>$user->id*10, 'uri'=>'principals/'.$user->login,'email'=>$user->email,'displayname'=>trim($user->firstname.' '.$user->lastname)), 77 | array('id'=>$user->id*10+1,'uri'=>'principals/'.$user->login.'/calendar-proxy-read','email'=>null,'displayname'=>null), 78 | array('id'=>$user->id*10+2,'uri'=>'principals/'.$user->login.'/calendar-proxy-write','email'=>null,'displayname'=>null), 79 | ); 80 | 81 | 82 | } 83 | 84 | 85 | /** 86 | * Returns the 'dirname' and 'basename' for a path. 87 | * 88 | * The reason there is a custom function for this purpose, is because 89 | * basename() is locale aware (behaviour changes if C locale or a UTF-8 locale is used) 90 | * and we need a method that just operates on UTF-8 characters. 91 | * 92 | * In addition basename and dirname are platform aware, and will treat backslash (\) as a 93 | * directory separator on windows. 94 | * 95 | * This method returns the 2 components as an array. 96 | * 97 | * If there is no dirname, it will return an empty string. Any / appearing at the end of the 98 | * string is stripped off. 99 | * 100 | * @param string $path 101 | * @return array 102 | */ 103 | static function splitPath($path) { 104 | 105 | $matches = array(); 106 | if(preg_match('/^(?:(?:(.*)(?:\/+))?([^\/]+))(?:\/?)$/u',$path,$matches)) { 107 | return array($matches[1],$matches[2]); 108 | } else { 109 | return array(null,null); 110 | } 111 | 112 | } 113 | 114 | /** 115 | * Returns a list of principals based on a prefix. 116 | * 117 | * This prefix will often contain something like 'principals'. You are only 118 | * expected to return principals that are in this base path. 119 | * 120 | * You are expected to return at least a 'uri' for every user, you can 121 | * return any additional properties if you wish so. Common properties are: 122 | * {DAV:}displayname 123 | * {http://sabredav.org/ns}email-address - This is a custom SabreDAV 124 | * field that's actualy injected in a number of other properties. If 125 | * you have an email address, use this property. 126 | * 127 | * @param string $prefixPath 128 | * @return array 129 | */ 130 | function getPrincipalsByPrefix($prefixPath) { 131 | 132 | $principals = []; 133 | 134 | foreach ($this->allprincipals as $row) { 135 | 136 | // Checking if the principal is in the prefix 137 | list($rowPrefix) = self::splitPath($row['uri']); 138 | if ($rowPrefix !== $prefixPath) continue; 139 | 140 | $principal = [ 141 | 'uri' => $row['uri'], 142 | ]; 143 | foreach ($this->fieldMap as $key => $value) { 144 | if ($row[$value['dbField']]) { 145 | $principal[$key] = $row[$value['dbField']]; 146 | } 147 | } 148 | $principals[] = $principal; 149 | } 150 | 151 | return $principals; 152 | 153 | } 154 | 155 | /** 156 | * Returns a specific principal, specified by it's path. 157 | * The returned structure should be the exact same as from 158 | * getPrincipalsByPrefix. 159 | * 160 | * @param string $path 161 | * @return array 162 | */ 163 | function getPrincipalByPath($path) { 164 | 165 | foreach ($this->allprincipals as $row) { 166 | if($row['uri']==$path) { 167 | 168 | $principal = [ 169 | 'id' => $row['id'], 170 | 'uri' => $row['uri'], 171 | ]; 172 | foreach ($this->fieldMap as $key => $value) { 173 | if ($row[$value['dbField']]) { 174 | $principal[$key] = $row[$value['dbField']]; 175 | } 176 | } 177 | return $principal; 178 | } 179 | } 180 | } 181 | 182 | /** 183 | * Updates one ore more webdav properties on a principal. 184 | * 185 | * The list of mutations is stored in a Sabre\DAV\PropPatch object. 186 | * To do the actual updates, you must tell this object which properties 187 | * you're going to process with the handle() method. 188 | * 189 | * Calling the handle method is like telling the PropPatch object "I 190 | * promise I can handle updating this property". 191 | * 192 | * Read the PropPatch documenation for more info and examples. 193 | * 194 | * @param string $path 195 | * @param DAV\PropPatch $propPatch 196 | */ 197 | function updatePrincipal($path, DAV\PropPatch $propPatch) { 198 | 199 | // not supported 200 | return false; 201 | 202 | } 203 | 204 | /** 205 | * This method is used to search for principals matching a set of 206 | * properties. 207 | * 208 | * This search is specifically used by RFC3744's principal-property-search 209 | * REPORT. 210 | * 211 | * The actual search should be a unicode-non-case-sensitive search. The 212 | * keys in searchProperties are the WebDAV property names, while the values 213 | * are the property values to search on. 214 | * 215 | * By default, if multiple properties are submitted to this method, the 216 | * various properties should be combined with 'AND'. If $test is set to 217 | * 'anyof', it should be combined using 'OR'. 218 | * 219 | * This method should simply return an array with full principal uri's. 220 | * 221 | * If somebody attempted to search on a property the backend does not 222 | * support, you should simply return 0 results. 223 | * 224 | * You can also just return 0 results if you choose to not support 225 | * searching at all, but keep in mind that this may stop certain features 226 | * from working. 227 | * 228 | * @param string $prefixPath 229 | * @param array $searchProperties 230 | * @param string $test 231 | * @return array 232 | */ 233 | function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { 234 | // not supported 235 | return array(); 236 | } 237 | 238 | /** 239 | * Returns the list of members for a group-principal 240 | * 241 | * @param string $principal 242 | * @return array 243 | */ 244 | function getGroupMemberSet($principal) { 245 | // not supported 246 | return array(); 247 | } 248 | 249 | /** 250 | * Returns the list of groups a principal is a member of 251 | * 252 | * @param string $principal 253 | * @return array 254 | */ 255 | function getGroupMembership($principal) { 256 | // not supported 257 | return array(); 258 | } 259 | 260 | /** 261 | * Updates the list of group members for a group principal. 262 | * 263 | * The principals should be passed as a list of uri's. 264 | * 265 | * @param string $principal 266 | * @param array $members 267 | * @return void 268 | */ 269 | function setGroupMemberSet($principal, array $members) { 270 | // not supported 271 | return; 272 | } 273 | 274 | /** 275 | * Creates a new principal. 276 | * 277 | * This method receives a full path for the new principal. The mkCol object 278 | * contains any additional webdav properties specified during the creation 279 | * of the principal. 280 | * 281 | * @param string $path 282 | * @param MkCol $mkCol 283 | * @return void 284 | */ 285 | function createPrincipal($path, MkCol $mkCol) { 286 | // not supported 287 | return; 288 | } 289 | 290 | } 291 | -------------------------------------------------------------------------------- /class/actions_cdav.class.php: -------------------------------------------------------------------------------- 1 | global->CDAV_GENTASK) || intval($conf->global->CDAV_GENTASK) == 0 || $parameters['currentcontext'] != 'projectcard') 27 | return 0; 28 | 29 | if ($action == "confirm_validate" && isset($object->id) && $object->id > 0) { 30 | //ok go ahead 31 | } elseif (GETPOST('status') != 1 && $action != "confirm_validateProject" || !isset($object->id) || $object->id <= 0) 32 | return 0; 33 | 34 | $CDAV_PROJ_USER_ROLE = $conf->global->CDAV_PROJ_USER_ROLE; // to pick good user in project 35 | $CDAV_TASK_USER_ROLE = $conf->global->CDAV_TASK_USER_ROLE; // role to put on task 36 | $CDAV_GENTASK_INI1 = $conf->global->CDAV_GENTASK_INI1; // initial service 37 | $CDAV_GENTASK_INI2 = $conf->global->CDAV_GENTASK_INI2; // initial service 38 | $CDAV_GENTASK_INI3 = $conf->global->CDAV_GENTASK_INI3; // initial service 39 | $CDAV_GENTASK_END1 = $conf->global->CDAV_GENTASK_END1; // final service 40 | $CDAV_GENTASK_END2 = $conf->global->CDAV_GENTASK_END2; // final service 41 | $CDAV_GENTASK_END3 = $conf->global->CDAV_GENTASK_END3; // final service 42 | $CDAV_GENTASK_SERVICE_TAG = $conf->global->CDAV_GENTASK_SERVICE_TAG; // restrict services 43 | $CDAV_EXTRAFIELD_DURATION = $conf->global->CDAV_EXTRAFIELD_DURATION; // duration in propaldet & commandedet extrafields 44 | $CDAV_TASK_HOUR_INI = $conf->global->CDAV_TASK_HOUR_INI; // begining of a working day 45 | $CDAV_TASK_HOUR_END = $conf->global->CDAV_TASK_HOUR_END; // ending of a working day 46 | 47 | if (isset($conf->global->WEEE_PRODUCT_ID) && intval($conf->global->WEEE_PRODUCT_ID) != 0) 48 | $WEEE_PRODUCT_ID = intval($conf->global->WEEE_PRODUCT_ID); // DEEE ? 49 | 50 | if ($action == "confirm_validate") { // button Validate 51 | $date_start = $object->date_start; 52 | $date_end = $object->date_end; 53 | } else // POST form 54 | { 55 | $date_start = dol_mktime(0, 0, 0, GETPOST('projectstartmonth', 'int'), GETPOST('projectstartday', 'int'), GETPOST('projectstartyear', 'int')); 56 | $date_end = dol_mktime(0, 0, 0, GETPOST('projectendmonth', 'int'), GETPOST('projectendday', 'int'), GETPOST('projectendyear', 'int')); 57 | } 58 | 59 | $error = 0; // Error counter 60 | //$myvalue = 'test'; // A result value 61 | 62 | // echo "action: " . $action; 63 | // echo "User "; 64 | // print_r($user); 65 | //echo "Object "; 66 | //print_r($object); 67 | 68 | // do something only for the context 'somecontext' 69 | 70 | $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "projet_task WHERE fk_projet = " . intval($object->id); 71 | $result = $db->query($sql); 72 | // echo "Result "; 73 | // print_r($result); 74 | if ($db->num_rows($result) == 0 && isset($user->rights->agenda->allactions->read)) { 75 | $db->free($result); 76 | //echo "NOTASK"; 77 | 78 | $rPreTasksLib = array(); 79 | $rPreTasksDesc = array(); 80 | $rPreTasksDuree = array(); 81 | $rPostTasksLib = array(); 82 | $rPostTasksDesc = array(); 83 | $rPostTasksDuree = array(); 84 | $rTasksLib = array(); 85 | $rTasksDesc = array(); 86 | $rTasksDuree = array(); 87 | 88 | // retrieve n pre-tasks [0-3] 89 | $i = 0; 90 | while (++$i <= 3) { 91 | if (isset(${'CDAV_GENTASK_INI' . $i}) && ${'CDAV_GENTASK_INI' . $i} > 0) { 92 | // Found CDAV_GENTASK_INI$i ==> ${'CDAV_GENTASK_INI' . $i} 93 | $sqldet = "SELECT label, description, duration FROM " . MAIN_DB_PREFIX . "product WHERE rowid = " . intval(${'CDAV_GENTASK_INI' . $i}); 94 | $querydet = $db->query($sqldet); 95 | while ($querydet && ($det = $db->fetch_object($querydet)) !== null) { 96 | $rPreTasksLib[] = $det->label; 97 | $rPreTasksDesc[] = $det->description; 98 | $rPreTasksDuree[] = $det->duration; 99 | } 100 | $db->free($querydet); 101 | unset($det); 102 | } 103 | } 104 | 105 | $bDocs = false; 106 | $rElmts = array(); // orders source's : $rElmts[propal_ID]=commande_ID 107 | 108 | $sql = " SELECT * FROM " . MAIN_DB_PREFIX . "commande WHERE fk_projet = " . intval($object->id) . " ORDER BY rowid"; 109 | $result = $db->query($sql); 110 | while ($result && ($res = $db->fetch_object($result)) !== null) { 111 | $bDocs = true; 112 | $sqldet = " SELECT det.*, pro.label as prod_label, pro.description as prod_description, pro.duration as prod_duration, elt.fk_source AS prop_source, ef.cdav_duration as cdav_duration 113 | FROM " . MAIN_DB_PREFIX . "commandedet AS det 114 | LEFT OUTER JOIN " . MAIN_DB_PREFIX . "product AS pro ON (pro.rowid=det.fk_product)"; 115 | if (isset($CDAV_GENTASK_SERVICE_TAG) && $CDAV_GENTASK_SERVICE_TAG > 0) 116 | $sqldet .= " LEFT OUTER JOIN " . MAIN_DB_PREFIX . "categorie_product AS cat ON (cat.fk_product=det.fk_product AND cat.fk_categorie = " . intval($CDAV_GENTASK_SERVICE_TAG) . ")"; 117 | 118 | $sqldet .= " LEFT OUTER JOIN " . MAIN_DB_PREFIX . "commandedet_extrafields AS ef ON (ef.fk_object=det.rowid)"; 119 | $sqldet .= " LEFT OUTER JOIN " . MAIN_DB_PREFIX . "element_element elt ON ( elt.sourcetype='propal' AND elt.targettype='commande' AND elt.fk_target = " . intval($res->rowid) . ") 120 | WHERE fk_commande = " . intval($res->rowid) . " AND qty > 0 AND product_type=1 "; 121 | if ($CDAV_GENTASK_SERVICE_TAG > 0 && $CDAV_EXTRAFIELD_DURATION !== false) 122 | $sqldet .= " AND (cat.fk_categorie IS NOT NULL OR COALESCE(ef.cdav_duration,'') <> '' )"; 123 | elseif ($CDAV_EXTRAFIELD_DURATION !== false) 124 | $sqldet .= " AND COALESCE(duration,'') <> '' "; 125 | elseif ($CDAV_GENTASK_SERVICE_TAG > 0) 126 | $sqldet .= " AND cat.fk_categorie IS NOT NULL"; 127 | $sqldet .= " ORDER BY rowid"; 128 | //echo "\n\n $sqldet \n\n"; 129 | 130 | $querydet = $db->query($sqldet); 131 | while ($querydet && ($det = $db->fetch_object($querydet)) !== null) { 132 | if (!is_null($det->prop_source) && $det->prop_source !== false) 133 | $rElmts[$det->prop_source] = $det->rowid; 134 | //else echo "\n\n NOSOURCE"; 135 | 136 | if (isset($WEEE_PRODUCT_ID) && $WEEE_PRODUCT_ID == $det->fk_product) 137 | continue; 138 | 139 | if (!empty($det->label)) 140 | $rTasksLib[] = $det->label; 141 | elseif (!empty($det->prod_label)) 142 | $rTasksLib[] = $det->prod_label; 143 | elseif (!empty($det->description)) 144 | $rTasksLib[] = strtok($det->description, "\n"); 145 | else $rTasksLib[] = 'Task'; 146 | 147 | if (!empty($det->description)) 148 | $rTasksDesc[] = $det->description; 149 | elseif (!empty($det->prod_description)) 150 | $rTasksDesc[] = $det->prod_description; 151 | else $rTasksDesc[] = ''; 152 | 153 | if (!empty($det->cdav_duration)) 154 | $rTasksDuree[] = $det->cdav_duration; 155 | elseif (!empty($det->prod_duration)) 156 | $rTasksDuree[] = $det->prod_duration; 157 | else $rTasksDuree[] = ''; 158 | } 159 | unset($det); 160 | $db->free($querydet); 161 | } 162 | $db->free($result); 163 | //var_dump($rElmts); 164 | $sql = " SELECT * FROM " . MAIN_DB_PREFIX . "propal WHERE fk_projet = " . intval($object->id); 165 | $query = $db->query($sql); 166 | while ($query && ($res = $db->fetch_object($query)) !== null) { 167 | $bDocs = true; 168 | if (isset($rElmts[$res->rowid])) 169 | continue; 170 | 171 | $sqldet = " SELECT det.*, pro.label as prod_label, pro.description as prod_description, pro.duration as prod_duration, ef.cdav_duration as cdav_duration 172 | FROM " . MAIN_DB_PREFIX . "propaldet AS det 173 | LEFT OUTER JOIN " . MAIN_DB_PREFIX . "product AS pro ON (pro.rowid=det.fk_product)"; 174 | if (isset($CDAV_GENTASK_SERVICE_TAG) && $CDAV_GENTASK_SERVICE_TAG > 0) 175 | $sqldet .= " LEFT OUTER JOIN " . MAIN_DB_PREFIX . "categorie_product AS cat ON (cat.fk_product=det.fk_product AND cat.fk_categorie = " . intval($CDAV_GENTASK_SERVICE_TAG) . ")"; 176 | 177 | $sqldet .= " LEFT OUTER JOIN " . MAIN_DB_PREFIX . "propaldet_extrafields AS ef ON (ef.fk_object=det.rowid)"; 178 | $sqldet .= " WHERE fk_propal = " . intval($res->rowid) . " AND qty > 0 AND product_type=1"; 179 | if ($CDAV_GENTASK_SERVICE_TAG > 0 && $CDAV_EXTRAFIELD_DURATION !== false) 180 | $sqldet .= " AND (cat.fk_categorie IS NOT NULL OR COALESCE(ef.cdav_duration,'') <> '' )"; 181 | elseif ($CDAV_EXTRAFIELD_DURATION !== false) 182 | $sqldet .= " AND COALESCE(ef.cdav_duration,'') <> '' "; 183 | elseif ($CDAV_GENTASK_SERVICE_TAG > 0) 184 | $sqldet .= " AND cat.fk_categorie IS NOT NULL"; 185 | $sqldet .= " ORDER BY rowid"; 186 | 187 | //echo "\n\n $sqldet \n\n"; 188 | $querydet = $db->query($sqldet); 189 | while ($querydet && ($det = $db->fetch_object($querydet)) !== null) { 190 | if (isset($WEEE_PRODUCT_ID) && $WEEE_PRODUCT_ID == $det->fk_product) 191 | continue; 192 | 193 | //if( !isset($CDAV_EXTRAFIELD_DURATION) || $CDAV_EXTRAFIELD_DURATION != true || empty($det->duration) ) 194 | // continue; 195 | 196 | if (!empty($det->label)) 197 | $rTasksLib[] = $det->label; 198 | elseif (!empty($det->prod_label)) 199 | $rTasksLib[] = $det->prod_label; 200 | elseif (!empty($det->description)) 201 | $rTasksLib[] = strtok($det->description, "\n"); 202 | else $rTasksLib[] = 'Task'; 203 | 204 | if (!empty($det->description)) 205 | $rTasksDesc[] = $det->description; 206 | elseif (!empty($det->prod_description)) 207 | $rTasksDesc[] = $det->prod_description; 208 | else $rTasksDesc[] = ''; 209 | 210 | if (!empty($det->cdav_duration)) 211 | $rTasksDuree[] = $det->cdav_duration; 212 | elseif (!empty($det->prod_duration)) 213 | $rTasksDuree[] = $det->prod_duration; 214 | else $rTasksDuree[] = ''; 215 | } 216 | unset($det); 217 | $db->free($querydet); 218 | } 219 | $db->free($query); 220 | $sql = "SELECT fk_socpeople FROM llx_element_contact WHERE fk_c_type_contact = " . intval($CDAV_PROJ_USER_ROLE) . " AND element_id = " . intval($object->id); 221 | $querydet = $db->query($sql); 222 | if ($querydet && ($row = $db->fetch_object($querydet)) !== null) 223 | $task_user = $row->fk_socpeople; 224 | else $task_user = $user->id; 225 | $db->free($querydet); 226 | // echo "\nrTasksLib "; 227 | // print_r($rTasksLib); 228 | 229 | 230 | if (count($rTasksLib) > 0 || $bDocs) { // create pre & post tasks even if no service in docs 231 | // retrieve n post-tasks [0-3] 232 | $i = 0; 233 | while (++$i <= 3) { 234 | if (isset(${'CDAV_GENTASK_END' . $i}) && ${'CDAV_GENTASK_END' . $i} > 0) { 235 | // Found CDAV_GENTASK_END$i ==> ${'CDAV_GENTASK_END' . $i} 236 | $sqldet = "SELECT label, description, duration FROM " . MAIN_DB_PREFIX . "product WHERE rowid = " . intval(${'CDAV_GENTASK_END' . $i}); 237 | $querydet = $db->query($sqldet); 238 | while ($querydet && ($det = $db->fetch_object($querydet)) !== null) { 239 | $rPostTasksLib[] = $det->label; 240 | $rPostTasksDesc[] = $det->description; 241 | $rPostTasksDuree[] = $det->duration; 242 | } 243 | $db->free($querydet); 244 | unset($det); 245 | } 246 | } 247 | 248 | // merging pre & post tasks 249 | $rTasksLib = array_merge_recursive($rPreTasksLib, $rTasksLib, $rPostTasksLib); 250 | $rTasksDesc = array_merge_recursive($rPreTasksDesc, $rTasksDesc, $rPostTasksDesc); 251 | $rTasksDuree = array_merge_recursive($rPreTasksDuree, $rTasksDuree, $rPostTasksDuree); 252 | 253 | //echo "\nrTasksDuree "; 254 | //print_r($rTasksDuree); 255 | //exit; 256 | 257 | // creating tasks 258 | 259 | $rechI = '/[ ]*([0123456789]*)[ ]*[i|min]/i'; 260 | $rechH = '/[ ]*([0123456789]*)[ ]*h/i'; 261 | $rechJ = '/[ ]*([0123456789]*)[ ]*[j|d|t]/i'; 262 | $rechS = '/[ ]*([0123456789]*)[ ]*[s|w]/i'; 263 | $hIni = 7; 264 | $hEnd = 19; 265 | if (!empty($CDAV_TASK_HOUR_INI)) 266 | $hIni = $CDAV_TASK_HOUR_INI; 267 | if (!empty($CDAV_TASK_HOUR_END)) 268 | $hEnd = $CDAV_TASK_HOUR_END; 269 | 270 | if (intval($hEnd) < intval($hIni)) { 271 | $hTmp = $hIni; 272 | $hIni = $hEnd; 273 | $hEnd = $hTmp; 274 | } 275 | 276 | foreach ($rTasksLib as $taskid => $label) { 277 | $defaultref = ''; 278 | $obj = empty($conf->global->PROJECT_TASK_ADDON) ? 'mod_task_simple' : $conf->global->PROJECT_TASK_ADDON; 279 | if (!empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT . "/core/modules/project/task/" . $conf->global->PROJECT_TASK_ADDON . ".php")) { 280 | require_once DOL_DOCUMENT_ROOT . "/core/modules/project/task/" . $conf->global->PROJECT_TASK_ADDON . '.php'; 281 | $modTask = new $obj; 282 | $defaultref = $modTask->getNextValue($object->thirdparty, null); 283 | } 284 | if (is_numeric($defaultref) && $defaultref <= 0) $defaultref = ''; 285 | 286 | $label = trim($label); 287 | $desc = trim(strip_tags($rTasksDesc[$taskid])); 288 | 289 | if (empty($label)) { 290 | $descLines = explode("\n", $desc); 291 | $label = trim($descLines[0]); 292 | } 293 | 294 | if (preg_match_all($rechI, $rTasksDuree[$taskid], $out0)) 295 | $task_duration = intval($out0[1][0]) * 60; 296 | elseif (preg_match_all($rechH, $rTasksDuree[$taskid], $out1)) { 297 | //if( $hIni + intval($out1[1][0]) <= 24 ) 298 | $task_duration = intval($out1[1][0]) * 3600; 299 | //else // too many hour for a single day, convert hours in working days after rounding 300 | // $task_duration = (intval($hEnd)-intval($hIni))*3600 + ( (round(intval($out[1][0])/($hEnd-$hIni))-1)*3600*24 ); 301 | } elseif (preg_match_all($rechJ, $rTasksDuree[$taskid], $out2)) 302 | $task_duration = (intval($hEnd) - intval($hIni)) * 3600 + ((intval($out2[1][0]) - 1) * 3600 * 24); 303 | elseif (preg_match_all($rechS, $rTasksDuree[$taskid], $out3)) 304 | $task_duration = (intval($hEnd) - intval($hIni)) * 3600 + (((intval($out3[1][0])) * 3600 * 24 * 7) - 24 * 3600); 305 | else $task_duration = 3600; 306 | 307 | $task = new Task($db); 308 | $task->ref = $defaultref; 309 | $task->fk_task_parent = 0; 310 | $task->fk_project = intval($object->id); 311 | $task->label = $label; 312 | $task->description = $desc; 313 | $task->fk_statut = 0; 314 | $task->date_c = time(); 315 | $task->date_start = $date_start + intval($hIni) * 3600; 316 | $task->date_end = $date_start + intval($hIni) * 3600 + $task_duration; 317 | $task->fk_user_creat = $user->id; 318 | $task->fk_user_valid = $user->id; 319 | 320 | $task_id = $task->create($user); 321 | // echo "Task "; 322 | // print_r($task); 323 | 324 | if ($task_id > 0) { 325 | $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_contact (`datecreate`, `statut`, `element_id`, `fk_c_type_contact`, `fk_socpeople` ) 326 | VALUES ( 327 | NOW(), 328 | 4, 329 | " . (int) $task_id . ", 330 | " . (int) $CDAV_TASK_USER_ROLE . ", 331 | " . (int) $task_user . " 332 | )"; 333 | } 334 | $db->query($sql); 335 | 336 | /*$ref = "TK".date("ym")."-".$tasknum; 337 | $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet_task (`ref`, `entity`, `fk_projet`, `datec`, `label`, `description`, ``, ``, ``, ``, ``) 338 | VALUES ( 339 | , 340 | , 341 | )";*/ 342 | 343 | //$db->query($sql); 344 | } 345 | } 346 | } 347 | 348 | 349 | /* 350 | if (! $error) 351 | { 352 | $this->results = array('myreturn' => $myvalue); 353 | $this->resprints = 'A text to show'; 354 | return 0; // or return 1 to replace standard code 355 | } 356 | else 357 | { 358 | $this->errors[] = 'Error message'; 359 | return -1; 360 | } 361 | */ 362 | return 0; 363 | } 364 | 365 | 366 | /** 367 | * Overloading the formObjectOptions function : replacing the parent's function with the one below 368 | * 369 | * @param array $parameters Hook metadatas (context, etc...) 370 | * @param CommonObject $object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) 371 | * @param string $action Current action (if set). Generally create or edit or null 372 | * @return int < 0 on error, 0 on success, 1 to replace standard code 373 | */ 374 | public function formObjectOptions($parameters, &$object, &$action) 375 | { 376 | global $user, $conf, $db; 377 | 378 | // echo "formObjectOptions parameters: "; 379 | // print_r($parameters); 380 | // echo "formObjectOptions object: "; 381 | // print_r($object); 382 | // echo "formObjectOptions action: "; 383 | // print_r($action); 384 | 385 | if ($parameters['currentcontext'] == 'projecttaskscard' && $parameters['id'] > 0) { 386 | $sql = 'SELECT pt.rowid, us.color, us.login, us.firstname, us.lastname 387 | FROM ' . MAIN_DB_PREFIX . 'projet_task AS pt 388 | LEFT JOIN ' . MAIN_DB_PREFIX . 'element_contact as ec ON (ec.element_id=pt.rowid) 389 | LEFT JOIN ' . MAIN_DB_PREFIX . 'user as us ON (us.rowid=ec.fk_socpeople) 390 | LEFT JOIN ' . MAIN_DB_PREFIX . 'c_type_contact as tc ON (tc.rowid=ec.fk_c_type_contact AND tc.element="project_task" AND tc.source="internal") 391 | WHERE tc.element="project_task" AND tc.source="internal" AND us.login IS NOT NULL 392 | AND pt.fk_projet=' . intval($parameters['id']) . ' AND pt.entity IN (' . getEntity('societe', 1) . ') 393 | ORDER BY pt.rowid, us.login'; 394 | $result = $db->query($sql); 395 | echo "\n\n"; 400 | } 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /core/modules/modCDav.class.php: -------------------------------------------------------------------------------- 1 | 3 | * Copyright (C) 2004-2012 Laurent Destailleur 4 | * Copyright (C) 2005-2012 Regis Houssin 5 | * Copyright (C) 2015 Befox SARL 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * \defgroup cdav Module CDav 23 | * \brief allows caldav and carddav clients to sync with Dolibarr. 24 | * \file htdocs/cdav/core/modules/modCDav.class.php 25 | * \ingroup cdav 26 | * \brief Description and activation file for module CDav 27 | */ 28 | include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; 29 | 30 | 31 | /** 32 | * Description and activation class for module CDav 33 | */ 34 | class modCDav extends DolibarrModules 35 | { 36 | /** 37 | * Constructor. Define names, constants, directories, boxes, permissions 38 | * 39 | * @param DoliDB $db Database handler 40 | */ 41 | function __construct($db) 42 | { 43 | global $langs,$conf; 44 | 45 | $this->db = $db; 46 | 47 | // Id for module (must be unique). 48 | // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). 49 | $this->numero = 562387; 50 | // Key text used to identify module (for permissions, menus, etc...) 51 | $this->rights_class = 'cdav'; 52 | 53 | // Family can be 'crm','financial','hr','projects','products','ecm','technic','other' 54 | // It is used to group modules in module setup page 55 | $this->family = "technic"; 56 | // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) 57 | $this->name = preg_replace('/^mod/i','',get_class($this)); 58 | // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module) 59 | $this->description = "Allows caldav and carddav clients to sync with Dolibarr."; 60 | // Possible values for version are: 'development', 'experimental', 'dolibarr' or version 61 | $this->version = '3.1.1'; 62 | // Key used in llx_const table to save module status enabled/disabled (where CDAV is value of property name of module in uppercase) 63 | $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); 64 | // Where to store the module in setup page (0=common,1=interface,2=others,3=very specific) 65 | $this->special = 1; 66 | // Name of image file used for this module. 67 | // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' 68 | // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' 69 | $this->picto='technic'; 70 | 71 | // Defined all module parts (triggers, login, substitutions, menus, css, etc...) 72 | // for default path (eg: /mymodule/core/xxxxx) (0=disable, 1=enable) 73 | // for specific path of parts (eg: /mymodule/core/modules/barcode) 74 | // for specific css file (eg: /mymodule/css/mymodule.css.php) 75 | //$this->module_parts = array( 76 | // 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) 77 | // 'login' => 0, // Set this to 1 if module has its own login method directory (core/login) 78 | // 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions) 79 | // 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus) 80 | // 'theme' => 0, // Set this to 1 if module has its own theme directory (theme) 81 | // 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl) 82 | // 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) 83 | // 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) 84 | // 'css' => array('/mymodule/css/mymodule.css.php'), // Set this to relative path of css file if module has its own css file 85 | // 'js' => array('/mymodule/js/mymodule.js'), // Set this to relative path of js file if module must load a js on all pages 86 | // 'hooks' => array('hookcontext1','hookcontext2') // Set here all hooks context managed by module 87 | // 'dir' => array('output' => 'othermodulename'), // To force the default directories names 88 | // 'workflow' => array('WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2'=>array('enabled'=>'! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', 'picto'=>'yourpicto@mymodule')) // Set here all workflow context managed by module 89 | // ); 90 | $this->module_parts = array( 91 | 'hooks' => array('projectcard', 'projecttaskscard'), 92 | ); 93 | 94 | // Data directories to create when module is enabled. 95 | // Example: this->dirs = array("/mymodule/temp"); 96 | $this->dirs = array('/cdav','/cdav/public'); 97 | 98 | // Config pages. Put here list of php page, stored into mymodule/admin directory, to use to setup module. 99 | $this->config_page_url = array('setup.php@cdav'); 100 | 101 | // Dependencies 102 | $this->hidden = false; // A condition to hide module 103 | $this->depends = array(); // List of modules id that must be enabled if this module is enabled 104 | $this->requiredby = array(); // List of modules id to disable if this one is disabled 105 | $this->conflictwith = array(); // List of modules id this module is in conflict with 106 | $this->phpmin = array(5,6); // Minimum version of PHP required by module 107 | $this->need_dolibarr_version = array(7,0); // Minimum version of Dolibarr required by module 108 | $this->langfiles = array(); 109 | 110 | // Constants 111 | // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) 112 | // Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), 113 | // 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) 114 | // ); 115 | $this->const = array( 116 | 0 => array('CDAV_URI_KEY', 'chaine', substr(md5(time()),0,8),'Change it to force client to resync',0,'current',0), 117 | 1 => array('CDAV_CONTACT_TAG', 'chaine', '', 'Contact tag to restrict contacts to sync, leave blank for all',0,'current',0), 118 | 2 => array('CDAV_THIRD_SYNC', 'chaine', '0', 'How to sync thirdparties',0,'current',0), 119 | 3 => array('CDAV_SYNC_PAST', 'chaine', '31', 'Number of days to sync before today',0,'current',0), 120 | 4 => array('CDAV_SYNC_FUTURE', 'chaine', '365', 'Number of days to sync after today',0,'current',0), 121 | 5 => array('CDAV_TASK_SYNC', 'chaine', '0', 'How to sync project tasks',0,'current',0), 122 | 6 => array('CDAV_GENTASK', 'chaine', '0', 'Convert documents to tasks',0,'current',0), 123 | 7 => array('CDAV_GENTASK_INI1', 'chaine', '0', 'Generate initial tasks from services',0,'current',0), 124 | 8 => array('CDAV_GENTASK_INI2', 'chaine', '0', 'Generate initial tasks from services',0,'current',0), 125 | 9 => array('CDAV_GENTASK_INI3', 'chaine', '0', 'Generate initial tasks from services',0,'current',0), 126 | 10 => array('CDAV_GENTASK_END1', 'chaine', '0', 'Generate final tasks from services',0,'current',0), 127 | 11 => array('CDAV_GENTASK_END2', 'chaine', '0', 'Generate final tasks from services',0,'current',0), 128 | 12 => array('CDAV_GENTASK_END3', 'chaine', '0', 'Generate final tasks from services',0,'current',0), 129 | 13 => array('CDAV_PROJ_USER_ROLE', 'chaine', '', 'Project user role to find default task owner',0,'current',0), 130 | 14 => array('CDAV_TASK_USER_ROLE', 'chaine', '', 'Project task user role when creating a new project task',0,'current',0), 131 | 15 => array('CDAV_GENTASK_SERVICE_TAG', 'chaine', '', 'Service tag to restrict services to be converted as task, leave blank to sync all',0,'current',0), 132 | 16 => array('CDAV_EXTRAFIELD_DURATION', 'chaine', '', 'Duration services',0,'current',0), 133 | 17 => array('CDAV_TASK_HOUR_INI', 'chaine', '', 'Begining of a working day',0,'current',0), 134 | 18 => array('CDAV_TASK_HOUR_END', 'chaine', '', 'Ending of a working day',0,'current',0), 135 | 19 => array('CDAV_QRCODE_DAVX5_ENABLED', 'chaine', '0', 'Activate DavX5 auto URL',0,'current',0), 136 | 20 => array('CDAV_MEMBER_SYNC', 'chaine', '0', 'Sync members',0,'current',0), 137 | ); 138 | 139 | // Array to add new pages in new tabs 140 | // Example: $this->tabs = array('objecttype:+tabname1:Title1:mylangfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1 141 | // 'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@mymodule:$user->rights->othermodule->read:/mymodule/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. 142 | // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname 143 | // where objecttype can be 144 | // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) 145 | // 'contact' to add a tab in contact view 146 | // 'contract' to add a tab in contract view 147 | // 'group' to add a tab in group view 148 | // 'intervention' to add a tab in intervention view 149 | // 'invoice' to add a tab in customer invoice view 150 | // 'invoice_supplier' to add a tab in supplier invoice view 151 | // 'member' to add a tab in fundation member view 152 | // 'opensurveypoll' to add a tab in opensurvey poll view 153 | // 'order' to add a tab in customer order view 154 | // 'order_supplier' to add a tab in supplier order view 155 | // 'payment' to add a tab in payment view 156 | // 'payment_supplier' to add a tab in supplier payment view 157 | // 'product' to add a tab in product view 158 | // 'propal' to add a tab in propal view 159 | // 'project' to add a tab in project view 160 | // 'stock' to add a tab in stock view 161 | // 'thirdparty' to add a tab in third party view 162 | // 'user' to add a tab in user view 163 | $this->tabs = array(); 164 | 165 | // Dictionaries 166 | if (! isset($conf->cdav->enabled)) 167 | { 168 | $conf->cdav=new stdClass(); 169 | $conf->cdav->enabled=0; 170 | } 171 | $this->dictionaries=array(); 172 | /* Example: 173 | if (! isset($conf->mymodule->enabled)) $conf->mymodule->enabled=0; // This is to avoid warnings 174 | $this->dictionaries=array( 175 | 'langs'=>'mylangfile@mymodule', 176 | 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor 177 | 'tablib'=>array("Table1","Table2","Table3"), // Label of tables 178 | 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields 179 | 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order 180 | 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) 181 | 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) 182 | 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) 183 | 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') 184 | 'tabcond'=>array($conf->mymodule->enabled,$conf->mymodule->enabled,$conf->mymodule->enabled) // Condition to show each dictionary 185 | ); 186 | */ 187 | 188 | // Boxes 189 | // Add here list of php file(s) stored in core/boxes that contains class to show a box. 190 | $this->boxes = array(); // List of boxes 191 | // Example: 192 | //$this->boxes=array(array(0=>array('file'=>'myboxa.php','note'=>'','enabledbydefaulton'=>'Home'),1=>array('file'=>'myboxb.php','note'=>''),2=>array('file'=>'myboxc.php','note'=>''));); 193 | 194 | // Permissions 195 | $this->rights = array(); // Permission array used by this module 196 | $r=0; 197 | 198 | // Add here list of permission defined by an id, a label, a boolean and two constant strings. 199 | // Example: 200 | // $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) 201 | // $this->rights[$r][1] = 'Permision label'; // Permission label 202 | // $this->rights[$r][3] = 1; // Permission by default for new user (0/1) 203 | // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 204 | // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) 205 | // $r++; 206 | 207 | 208 | // Main menu entries 209 | $this->menu = array(); // List of menus to add 210 | $r=0; 211 | 212 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=companies,fk_leftmenu=contacts', // Put 0 if this is a top menu 213 | 'type'=>'left', // This is a Top menu entry 214 | 'titre'=>'CardDAVurl', 215 | 'mainmenu'=>'companies', 216 | 'leftmenu'=>'contacts', 217 | 'url'=>'/cdav/cdavurls.php?type=CardDAV&leftmenu=contacts', 218 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 219 | 'position'=>190, 220 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. 221 | 'perms'=>'$user->rights->societe->contact->lire', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 222 | 'target'=>'', 223 | 'user'=>0); 224 | 225 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=agenda', // Put 0 if this is a top menu 226 | 'type'=>'left', // This is a Top menu entry 227 | 'titre'=>'CalDAVurl', 228 | 'mainmenu'=>'agenda', 229 | 'url'=>'/cdav/cdavurls.php?type=CalDAV&mainmenu=agenda', 230 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 231 | 'position'=>190, 232 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. 233 | 'perms'=>'$user->rights->agenda->myactions->read', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 234 | 'target'=>'', 235 | 'user'=>0); 236 | 237 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=agenda', // Put 0 if this is a top menu 238 | 'type'=>'left', // This is a Top menu entry 239 | 'titre'=>'ICSurl', 240 | 'mainmenu'=>'agenda', 241 | 'url'=>'/cdav/cdavurls.php?type=ICS&mainmenu=agenda', 242 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 243 | 'position'=>190, 244 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. 245 | 'perms'=>'$user->rights->agenda->myactions->read', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 246 | 'target'=>'', 247 | 'user'=>0); 248 | // Add here entries to declare new menus 249 | // 250 | // Example to declare a new Top Menu entry and its Left menu entry: 251 | // $this->menu[$r]=array( 'fk_menu'=>0, // Put 0 if this is a top menu 252 | // 'type'=>'top', // This is a Top menu entry 253 | // 'titre'=>'MyModule top menu', 254 | // 'mainmenu'=>'mymodule', 255 | // 'leftmenu'=>'mymodule', 256 | // 'url'=>'/mymodule/pagetop.php', 257 | // 'langs'=>'mylangfile@mymodule', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 258 | // 'position'=>100, 259 | // 'enabled'=>'$conf->mymodule->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. 260 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 261 | // 'target'=>'', 262 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 263 | // $r++; 264 | // 265 | // Example to declare a Left Menu entry into an existing Top menu entry: 266 | // $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=xxx', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 267 | // 'type'=>'left', // This is a Left menu entry 268 | // 'titre'=>'MyModule left menu', 269 | // 'mainmenu'=>'xxx', 270 | // 'leftmenu'=>'mymodule', 271 | // 'url'=>'/mymodule/pagelevel2.php', 272 | // 'langs'=>'mylangfile@mymodule', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 273 | // 'position'=>100, 274 | // 'enabled'=>'$conf->mymodule->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. 275 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 276 | // 'target'=>'', 277 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 278 | // $r++; 279 | 280 | 281 | // Exports 282 | $r=1; 283 | 284 | // Example: 285 | // $this->export_code[$r]=$this->rights_class.'_'.$r; 286 | // $this->export_label[$r]='CustomersInvoicesAndInvoiceLines'; // Translation key (used only if key ExportDataset_xxx_z not found) 287 | // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled. 288 | // $this->export_permission[$r]=array(array("facture","facture","export")); 289 | // $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef'); 290 | // $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product'); 291 | // $this->export_sql_start[$r]='SELECT DISTINCT '; 292 | // $this->export_sql_end[$r] =' FROM ('.MAIN_DB_PREFIX.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)'; 293 | // $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)'; 294 | // $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture'; 295 | // $this->export_sql_order[$r] .=' ORDER BY s.nom'; 296 | // $r++; 297 | } 298 | 299 | /** 300 | * Function called when module is enabled. 301 | * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. 302 | * It also creates data directories 303 | * 304 | * @param string $options Options when enabling module ('', 'noboxes') 305 | * @return int 1 if OK, 0 if KO 306 | */ 307 | function init($options='') 308 | { 309 | global $langs; 310 | $sql = array(); 311 | 312 | // Create 2 extrafields 313 | include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; 314 | $extrafields_cmd = new ExtraFields($this->db); 315 | 316 | try 317 | { 318 | //function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $computed='', $entity='', $langfile='', $enabled='1') 319 | $result_cmd=$extrafields_cmd->addExtraField('cdav_duration', $langs->trans("DurationEx"), 'varchar', 1, '10', 'commandedet', 0, 0, '', '', 1, '', '1'); 320 | if( ! $result_cmd ) 321 | { 322 | $this->error=$extrafields_cmd->error; 323 | } 324 | $extrafields_prop = new ExtraFields($this->db); 325 | $result_prop=$extrafields_prop->addExtraField('cdav_duration', $langs->trans("DurationEx"), 'varchar', 1, '10', 'propaldet', 0, 0, '', '', 1, '', '1'); 326 | if( ! $result_prop ) 327 | { 328 | $this->error=$extrafields_prop->error; 329 | } 330 | 331 | $result=$this->_load_tables('/cdav/sql/'); 332 | } 333 | catch(Exception $ex) 334 | { 335 | $this->error = $ex->getMessage(); 336 | } 337 | 338 | return $this->_init($sql, $options); 339 | } 340 | 341 | /** 342 | * Function called when module is disabled. 343 | * Remove from database constants, boxes and permissions from Dolibarr database. 344 | * Data directories are not deleted 345 | * 346 | * @param string $options Options when enabling module ('', 'noboxes') 347 | * @return int 1 if OK, 0 if KO 348 | */ 349 | function remove($options='') 350 | { 351 | $sql = array(); 352 | 353 | return $this->_remove($sql, $options); 354 | } 355 | 356 | } 357 | 358 | -------------------------------------------------------------------------------- /doc/description_en.html: -------------------------------------------------------------------------------- 1 |

Dolibarr module to synchronize calendars, project tasks and address book from CalDAV/CardDAV/ICS client tools such as Mozilla Thunderbird/Lightning or Android DAVDroid. Dolibarr becomes a CalDAV/CardDAV server.

2 | -------------------------------------------------------------------------------- /doc/description_fr.html: -------------------------------------------------------------------------------- 1 |

Module Dolibarr pour synchroniser les agendas, tâches de projet et carnet d'adresses depuis des outils client CalDAV/CardDAV/ICS tel que Mozilla Thunderbird/Lightning ou Android DAVDroid. Dolibarr devient un serveur CalDAV/CardDAV.

2 | -------------------------------------------------------------------------------- /doc/description_lo_en.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Dolibarr module to synchronize calendars, project tasks and address 12 | book from CalDAV/CardDAV/ICS client tools such as Mozilla 13 | Thunderbird/Lightning or Android DAVx5. Dolibarr becomes a 14 | CalDAV/CardDAV server.

15 |

Since version 2, this module allows to sync tasks, which can be 16 | created (according to setup) in projects from docs like proposals or 17 | orders.

18 |

You obtain a great tool for driving your tech teams !

19 | 20 | 21 | -------------------------------------------------------------------------------- /doc/description_lo_fr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Module Dolibarr pour synchroniser les agendas, tâches de projet et 12 | carnet d'adresses depuis des outils client CalDAV/CardDAV/ICS tel que 13 | Mozilla Thunderbird/Lightning ou Android DAVx5. Dolibarr devient un 14 | serveur CalDAV/CardDAV.

15 |

A partir de la version 2, le module permet de synchroniser aussi 16 | les tâches des projets, qui peuvent être créées de façon 17 | paramétrable depuis les documents de type propositions ou commandes.

18 |

Vous obtenez alors un outil de planification d’intervention pour 19 | vos équipes sur le terrain !

20 |


21 |
22 | 23 |

24 | 25 | 26 | -------------------------------------------------------------------------------- /doc/documentation_lo_en.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/documentation_lo_en.odt -------------------------------------------------------------------------------- /doc/documentation_lo_en.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/documentation_lo_en.pdf -------------------------------------------------------------------------------- /doc/logo_cdav_fil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/logo_cdav_fil.png -------------------------------------------------------------------------------- /doc/logo_cdav_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/logo_cdav_v2.png -------------------------------------------------------------------------------- /doc/long-description_en.html: -------------------------------------------------------------------------------- 1 |

CardDAV / CalDAV and ICS synchronisation. It uses included Sabre/DAV library.

2 |

You can :

3 |
    4 |
  • Read and Edit Dolibarr calendars through CalDAV
  • 5 |
  • Read and Edit Dolibarr project tasks through CalDAV
  • 6 |
  • Read and Edit Dolibarr addressBooks through CardDAV
  • 7 |
  • Read Dolibarr calendars through ICS Full version or only Free/Busy (hide details)
  • 8 |
  • Access Dolibarr documents through WebDAV (if admin)
  • 9 |
10 |

Each user can access his/her contacts address book (public and own private contacts), his/her own calendar and other users calendars according to his/her rights.

11 |

Dolibarr contact informations fill personnal informations in client software cards.

12 |

Society informations (to which contact is attached) fill professional informations in client software cards.

13 |

Cards updated in client software fill only Dolibarr contacts (not Society).

14 |

It is possible to select which contacts to sync with CDAV_CONTACT_TAG configuration value in Home / Setup / Other setup. Enter a contact tag value and then only contacts with this tag will be synced (empty value for all).

15 |

Calendar records with "Status / Percentage" set to "Not applicable" are converted to events in CalDAV (VEVENT), others are converted to tasks (VTODO).

16 |

Recurring events are not handled.

17 |

Module version: auto
Publisher/Licence: Befox SARL / GPLv3
User interface language: English/French
Help/Support: http://www.befox.fr/contact
Prerequisites:

18 |
    19 |
  • Dolibarr min version: auto
  • 20 |
  • Dolibarr max version: auto
  • 21 |
22 |

Install:

23 |
    24 |
  • Download the archive file of module (.zip file) from web site DoliStore.com
  • 25 |
  • Put the file into the root directory of Dolibarr.
  • 26 |
  • Uncompress the zip file, for example with command
  • 27 |
28 |
29 |
30 |
unzip modulefile.zip
31 |
32 |
33 |
    34 |
  • Module is then available and can be activated.
  • 35 |
36 | -------------------------------------------------------------------------------- /doc/long-description_fr.html: -------------------------------------------------------------------------------- 1 |

Synchronisation CardDAV / CalDAV et ICS. Ce module inclut la bibliothèque Sabre/DAV.

2 |

Vous pouvez :

3 |
    4 |
  • Lire et éditer les agendas Dolibarr au travers de CalDAV
  • 5 |
  • Lire et éditer les tâches de projet au travers de CalDAV
  • 6 |
  • Lire et éditer les carnets d'adresse au travers de CardDAV
  • 7 |
  • Lire les agendas Dolibarr au travers d'ICS en vue complète ou en vue libre/occupé (detail masqué)
  • 8 |
  • Accéder aux documents Dolibarr au travers de WebDAV (si utilisateur admin)
  • 9 |
10 |

Chaque utilisateur accède à ses contacts (publics ou ses contacts privés), à son agenda et ceux des autres utilisateurs en fonction de ses droits.

11 |

Les informations de contact Dolibarr remplissent les champs personnels de la fiche contact.

12 |

Les informations de tiers Dolibarr remplissent les champs professionnels de la fiche contact associée.

13 |

Les fiches contact mise à jour sur le logiciel client n'alimentent que le contact Dolibarr (le Tiers n'est jamais modifié).

14 |

Il est possible de sélectionner quels contacts sont synchronisés en spécifiant la catégorie/tag des contacts concernés. Par défaut tous les contacts sont synchronisés.

15 |

Les enregistrement d'agenda avec un "Statut / Pourcentage" à "Non applicable" sont convertis en évènements CalDAV (VEVENT), les autres sont convertis en tâches (VTODO).

16 |

Les évènements récurrents ne sont pas gérés.

17 |

Module version: auto
Editeur/Licence: Befox SARL / GPLv3
Langage interface: Anglais
Assistance: http://www.befox.fr/contact
Prérequis:

18 |
    19 |
  • Dolibarr min version: auto
  • 20 |
  • Dolibarr max version: auto
  • 21 |
22 |

Installation:

23 |
    24 |
  • Télécharger le fichier archive du module (.zip) depuis le site web DoliStore.com
  • 25 |
  • Placer le fichier dans le répertoire racine de dolibarr.
  • 26 |
  • Decompressez le fichier zip, par exemple par la commande
  • 27 |
28 |
29 |
30 |
unzip fichiermodule.zip
31 |
32 |
33 |
    34 |
  • Le module est alors disponible et activable.
  • 35 |
36 | -------------------------------------------------------------------------------- /doc/long-description_lo_en.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 |

CardDAV / CalDAV and ICS synchronisation. It uses included 15 | Sabre/DAV library.

16 |

You can :

17 |
    18 |
  • 19 |

    Read and Edit Dolibarr calendars 20 | through CalDAV 21 |

    22 |
  • 23 |
  • 24 |

    Read and Edit Dolibarr project tasks 25 | through CalDAV 26 |

    27 |
  • 28 |

    Read and Edit Dolibarr 29 | addressBooks through CardDAV 30 |

    31 |
  • 32 |

    Read Dolibarr calendars through 33 | ICS Full version or only Free/Busy (hide details) 34 |

    35 |
  • 36 |

    Access Dolibarr documents through WebDAV (if admin) 37 |

    38 |
39 |

Each user can access his/her contacts address book (public and own 40 | private contacts), his/her own calendar and other users calendars 41 | according to his/her rights.

42 |

Dolibarr contact informations fill personnal informations in 43 | client software cards.

44 |

Society informations (to which contact is attached) fill 45 | professional informations in client software cards.

46 |

Cards updated in client software fill only Dolibarr contacts (not 47 | Society).

48 |

It is possible to select which contacts to sync with 49 | CDAV_CONTACT_TAG configuration value in Home / Setup / Other setup. 50 | Enter a contact tag value and then only contacts with this tag will 51 | be synced (empty value for all).

52 |

Calendar records with "Status / Percentage" set to "Not 53 | applicable" are converted to events in CalDAV (VEVENT), others 54 | are converted to tasks (VTODO).
55 | Recurring events are not 56 | handled.

57 |

Project tasks are synchronized to the calendar and/or 58 | remote tasks (no duplication in Dolibarr). Tasks descriptions 59 | containing lines beginning with “- “ generate new items that can 60 | then be checked, which advance the percentage of completion (Declared 61 | progress)
62 | Previously, task generation can be created 63 | automatically from documents attached to the project (proposals and / 64 | or orders) in a customizable way.

65 |

Module version: auto
66 | Publisher/Licence: 67 | Befox SARL / GPLv3
68 | User 69 | interface language: English/French
70 | Help/Support: 71 | http://www.befox.fr/contact
72 | Prerequisites:

73 |
    74 |
  • 75 |

    Dolibarr min version: auto 76 |

    77 |
  • 78 |

    Dolibarr max version: auto 79 |

    80 |
81 |

Install:

82 |
    83 |
  • 84 |

    Download the archive file of 85 | module (.zip file) from web site DoliStore.com 86 |

    87 |
  • 88 |

    Put the file into the root 89 | directory of Dolibarr. 90 |

    91 |
  • 92 |

    Uncompress the zip file, for example with command 93 |

    94 |
95 |
unzip modulefile.zip
96 |
    97 |
  • 98 |

    Module is then available and can be activated. 99 |

    100 |
101 | 102 | 103 | -------------------------------------------------------------------------------- /doc/long-description_lo_fr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 |

Synchronisation CardDAV / CalDAV et ICS. Ce module inclut la 15 | bibliothèque Sabre/DAV.

16 |

Vous pouvez :

17 |
    18 |
  • 19 |

    Lire et éditer les agendas 20 | Dolibarr au travers de CalDAV 21 |

    22 |
  • 23 |
  • 24 |

    Lire et éditer les tâches de projet 25 | Dolibarr au travers de CalDAV 26 |

    27 |
  • 28 |

    Lire et éditer les carnets 29 | d'adresse au travers de CardDAV 30 |

    31 |
  • 32 |

    Lire les agendas Dolibarr au 33 | travers d'ICS en vue complète ou en vue libre/occupé (détail 34 | masqué) 35 |

    36 |
  • 37 |

    Lire et éditer les tâches 38 | Dolibarr au travers de CalDAV 39 |

    40 |
  • 41 |

    Accéder aux documents Dolibarr au travers de WebDAV (si 42 | utilisateur admin) 43 |

    44 |
45 |

Chaque utilisateur accède à ses contacts (publics ou ses 46 | contacts privés), à son agenda et ceux des autres utilisateurs en 47 | fonction de ses droits, à ses tâches et celles des autres 48 | utilisateurs en fonction de ses droits.

49 |

Les informations de contact Dolibarr remplissent les champs 50 | personnels de la fiche contact.

51 |

Les informations de tiers Dolibarr remplissent les champs 52 | professionnels de la fiche contact associée.

53 |

Les fiches contact mise à jour sur le logiciel client 54 | n'alimentent que le contact Dolibarr (le Tiers n'est jamais modifié).

55 |

Il est possible de sélectionner quels contacts sont synchronisés 56 | en spécifiant la catégorie/tag des contacts concernés. Par défaut 57 | tous les contacts sont synchronisés.

58 |

Les enregistrement d'agenda avec un "Statut / Pourcentage" 59 | à "Non applicable" sont convertis en évènements CalDAV 60 | (VEVENT), les autres sont convertis en tâches (VTODO).
61 | Les 62 | évènements récurrents ne sont pas gérés.

63 |

Les tâches des projets sont synchronisées vers l’agenda et/ou 64 | les tâches distants (pas de duplication dans Dolibarr). La 65 | description des tâches contenant des lignes commençant par «- » 66 | génèrent des items sur le terrain qui peuvent alors être cochés 67 | et faire avancer le pourcentage de réalisation de la tâches 68 | ( Progression déclarée – Declared progress )
69 | Auparavant, 70 | la génération des tâches peuvent être créées automatiquement en 71 | provenance de documents attachés au projet (propositions et/ou 72 | commandes) et ce, de façon paramétrable.

73 |


74 |
75 | 76 |

77 |

Module version: auto
78 | Editeur/Licence: Befox 79 | SARL / GPLv3
80 | Langage interface: 81 | Anglais
82 | Assistance: 83 | http://www.befox.fr/contact
84 | Prérequis:

85 |
    86 |
  • 87 |

    Dolibarr min version: auto 88 |

    89 |
  • 90 |

    Dolibarr max version: auto 91 |

    92 |
93 |

Installation:

94 |
    95 |
  • 96 |

    Télécharger le fichier archive 97 | du module (.zip) depuis le site web DoliStore.com 98 |

    99 |
  • 100 |

    Placer le fichier dans le 101 | répertoire racine de dolibarr. 102 |

    103 |
  • 104 |

    Decompressez le fichier zip, par exemple par la commande 105 |

    106 |
107 |
unzip fichiermodule.zip
108 |
    109 |
  • 110 |

    Le module est alors disponible et activable. 111 |

    112 |
113 | 114 | 115 | -------------------------------------------------------------------------------- /ics.php: -------------------------------------------------------------------------------- 1 | 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } 38 | if (!$res && $i > 0 && @file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; 39 | if (!$res && $i > 0 && @file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; 40 | // Try main.inc.php using relative path 41 | if (!$res && @file_exists("../main.inc.php")) $res = @include "../main.inc.php"; 42 | if (!$res && @file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; 43 | if (!$res && @file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; 44 | if (!$res) die("Include of main fails"); 45 | 46 | require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; 47 | 48 | // Load traductions files requiredby by page 49 | $langs->load("cdav"); 50 | 51 | 52 | //Get all event 53 | require_once './lib/cdav.lib.php'; 54 | 55 | 56 | // define CDAV_CONTACT_TAG if not 57 | if(!defined('CDAV_CONTACT_TAG')) 58 | { 59 | if(isset($conf->global->CDAV_CONTACT_TAG)) 60 | define('CDAV_CONTACT_TAG', $conf->global->CDAV_CONTACT_TAG); 61 | else 62 | define('CDAV_CONTACT_TAG', ''); 63 | } 64 | 65 | // define CDAV_URI_KEY if not 66 | if(!defined('CDAV_URI_KEY')) 67 | { 68 | if(isset($conf->global->CDAV_URI_KEY)) 69 | define('CDAV_URI_KEY', $conf->global->CDAV_URI_KEY); 70 | else 71 | define('CDAV_URI_KEY', substr(md5($_SERVER['HTTP_HOST']),0,8)); 72 | } 73 | 74 | // define CDAV_TASK_USER_ROLE if not 75 | if(!defined('CDAV_TASK_USER_ROLE')) 76 | { 77 | if(isset($conf->global->CDAV_TASK_USER_ROLE)) 78 | define('CDAV_TASK_USER_ROLE', $conf->global->CDAV_TASK_USER_ROLE); 79 | else 80 | die('Module CDav is not properly configured : Project user role not set !'); 81 | } 82 | 83 | // define CDAV_SYNC_PAST if not 84 | if(!defined('CDAV_SYNC_PAST')) 85 | { 86 | if(isset($conf->global->CDAV_SYNC_PAST)) 87 | define('CDAV_SYNC_PAST', $conf->global->CDAV_SYNC_PAST); 88 | else 89 | die('Module CDav is not properly configured : Period to sync not set !'); 90 | } 91 | 92 | // define CDAV_SYNC_FUTURE if not 93 | if(!defined('CDAV_SYNC_FUTURE')) 94 | { 95 | if(isset($conf->global->CDAV_SYNC_FUTURE)) 96 | define('CDAV_SYNC_FUTURE', $conf->global->CDAV_SYNC_FUTURE); 97 | else 98 | die('Module CDav is not properly configured : Period to sync not set !'); 99 | } 100 | 101 | // define CDAV_TASK_SYNC if not 102 | if(!defined('CDAV_TASK_SYNC')) 103 | { 104 | if(isset($conf->global->CDAV_TASK_SYNC)) 105 | define('CDAV_TASK_SYNC', $conf->global->CDAV_TASK_SYNC); 106 | else 107 | define('CDAV_TASK_SYNC', '0'); 108 | } 109 | 110 | // define CDAV_THIRD_SYNC if not 111 | if(!defined('CDAV_THIRD_SYNC')) 112 | { 113 | if(isset($conf->global->CDAV_THIRD_SYNC)) 114 | define('CDAV_THIRD_SYNC', $conf->global->CDAV_THIRD_SYNC); 115 | else 116 | define('CDAV_THIRD_SYNC', '0'); 117 | } 118 | 119 | // define CDAV_MEMBER_SYNC if not 120 | if(!defined('CDAV_MEMBER_SYNC')) 121 | { 122 | if(isset($conf->global->CDAV_MEMBER_SYNC)) 123 | define('CDAV_MEMBER_SYNC', $conf->global->CDAV_MEMBER_SYNC); 124 | else 125 | define('CDAV_MEMBER_SYNC', '0'); 126 | } 127 | 128 | // 0 < CDAV_ADDRESSBOOK_ID_SHIFT = Contacts 129 | // CDAV_ADDRESSBOOK_ID_SHIFT < 2*CDAV_ADDRESSBOOK_ID_SHIFT = Thirdparties 130 | // 2*CDAV_ADDRESSBOOK_ID_SHIFT < 3*CDAV_ADDRESSBOOK_ID_SHIFT = Members 131 | define('CDAV_ADDRESSBOOK_ID_SHIFT', 100000); 132 | 133 | //parse Token 134 | $arrTmp = explode('+ø+', openssl_decrypt(base64url_decode(GETPOST('token')), 'aes-256-cbc', CDAV_URI_KEY, true)); 135 | 136 | if(!is_array($arrTmp) || count($arrTmp)<2) 137 | { 138 | // use old encryption algo bf-ecb 139 | $arrTmp = explode('+ø+', openssl_decrypt(base64url_decode(GETPOST('token')), 'bf-ecb', CDAV_URI_KEY, true)); 140 | } 141 | 142 | if (! isset($arrTmp[1]) || ! in_array(trim($arrTmp[1]), array('nolabel', 'full'))) 143 | { 144 | echo 'Unauthorized Access !'; 145 | exit; 146 | } 147 | 148 | $id = trim($arrTmp[0]); 149 | $type = trim($arrTmp[1]); 150 | 151 | header('Content-type: text/calendar; charset=utf-8'); 152 | header('Content-Disposition: attachment; filename=Calendar-'.$id.'-'.$type.'.ics'); 153 | 154 | //fake user having right on this calendar 155 | $user = new stdClass(); 156 | 157 | $user->rights = new stdClass(); 158 | $user->rights->agenda = new stdClass(); 159 | $user->rights->agenda->myactions = new stdClass(); 160 | $user->rights->agenda->allactions = new stdClass(); 161 | $user->rights->societe = new stdClass(); 162 | $user->rights->societe->client = new stdClass(); 163 | 164 | $user->id = $id; 165 | $user->rights->agenda->myactions->read = true; 166 | $user->rights->agenda->allactions->read = true; 167 | $user->rights->societe->client->voir = false; 168 | 169 | $cdavLib = new CdavLib($user, $db, $langs); 170 | 171 | //Format them 172 | $arrEvents = $cdavLib->getFullCalendarObjects($id, true); 173 | 174 | echo "BEGIN:VCALENDAR\n"; 175 | echo "VERSION:2.0\n"; 176 | echo "PRODID:-//Dolibarr CDav//FR\n"; 177 | foreach($arrEvents as $event) 178 | { 179 | if ($type == 'nolabel') 180 | { 181 | //Remove SUMMARY / DESCRIPTION / LOCATION 182 | $event['calendardata'] = preg_replace('#SUMMARY:.*[^\n]#', 'SUMMARY:'.$langs->trans('Busy'), $event['calendardata']);//FIXME translate busy !! 183 | $event['calendardata'] = preg_replace('#DESCRIPTION:.*[^\n]#', 'DESCRIPTION:.', $event['calendardata']); 184 | $event['calendardata'] = preg_replace('#LOCATION:.*[^\n]#', 'LOCATION:', $event['calendardata']); 185 | echo $event['calendardata']; 186 | } 187 | else 188 | echo $event['calendardata']; 189 | } 190 | echo "END:VCALENDAR\n"; 191 | -------------------------------------------------------------------------------- /img/object_cdav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/img/object_cdav.png -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | BinaryEye (available on F-Droid) to flash the qrcode and autoconfig DavX5! 17 | -------------------------------------------------------------------------------- /langs/fr_FR/cdav.lang: -------------------------------------------------------------------------------- 1 | # Dolibarr language file - Source file is en_US - cdav 2 | CardDAVurl=URL CardDAV 3 | CalDAVurl=URL CalDAV 4 | ICSurl=URL ICS 5 | URLforICS=Cette URL peut être utilisée avec un client de synchronisation (lecture seule) : 6 | Full=Complet 7 | NoLabel=Sans label 8 | Busy=Occupé 9 | URLGeneric=Ces URL peuvent être utilisées avec un client de synchronisation CalDAV/CardDAV : 10 | URLforCardDAV=Si votre client ne détecte pas votre carnet d'adresse cette URL complète peut être précisée : 11 | URLforCalDAV=Si votre client ne détecte pas vos agendas ces URLs complètes peuvent être précisées : 12 | DurationEx=Durée (ex: 4H, 3J) 13 | ActivateDavX5autoURL=Activer la génération de qrcode d'auto configuration pour davx5 ? 14 | ActivateDavX5autoURLTooltip=Si vous activez cette option un qrcode d'auto-configuration vous sera proposé pour ne pas avoir à saisir toutes les données à la main sur votre smartphone 15 | URLForDavX5=Configuration automatique pour DavX5 16 | URLForDavX5Tooltip=Utilisez le logiciel libre BinaryEye (dispo sur F-Droid) pour flasher le qrcode et autoconfigurer DavX5 ! 17 | 18 | EnableMembersSync=Enable members sync 19 | GenerateAddressbookForMembership=Generate an address book for membership 20 | -------------------------------------------------------------------------------- /lib/cdav.lib.php: -------------------------------------------------------------------------------- 1 | user = $user; 21 | $this->db = $db; 22 | $this->langs = $langs; 23 | } 24 | 25 | /** 26 | * Base sql request for calendar events 27 | * 28 | * @param int calendar user id 29 | * @param int actioncomm object id 30 | * @return string 31 | */ 32 | public function getSqlCalEvents($calid, $oid=false, $ouri=false) 33 | { 34 | // TODO : replace GROUP_CONCAT by 35 | $sql = 'SELECT 36 | "ev" elem_source, 37 | a.tms AS lastupd, 38 | a.*, 39 | sp.firstname, 40 | sp.lastname, 41 | sp.address, 42 | sp.zip, 43 | sp.town, 44 | co.label country_label, 45 | sp.phone, 46 | sp.phone_perso, 47 | sp.phone_mobile, 48 | s.nom AS soc_nom, 49 | s.address soc_address, 50 | s.zip soc_zip, 51 | s.town soc_town, 52 | cos.label soc_country_label, 53 | s.phone soc_phone, 54 | p.ref proj_ref, 55 | p.title proj_title, 56 | p.description proj_desc, 57 | ac.sourceuid, 58 | (SELECT GROUP_CONCAT(u.login) FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar 59 | LEFT OUTER JOIN '.MAIN_DB_PREFIX.'user AS u ON (u.rowid=fk_element) 60 | WHERE ar.element_type=\'user\' AND fk_actioncomm=a.id) AS other_users 61 | FROM '.MAIN_DB_PREFIX.'actioncomm AS a'; 62 | if (! $this->user->rights->societe->client->voir )//FIXME si 'voir' on voit plus de chose ? 63 | { 64 | $sql.=' LEFT OUTER JOIN '.MAIN_DB_PREFIX.'societe_commerciaux AS sc ON (a.fk_soc = sc.fk_soc AND sc.fk_user='.$this->user->id.') 65 | LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = sc.fk_soc) 66 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.fk_soc = sc.fk_soc AND sp.rowid = a.fk_contact) 67 | LEFT JOIN '.MAIN_DB_PREFIX.'actioncomm_cdav AS ac ON (a.id = ac.fk_object)'; 68 | } 69 | else 70 | { 71 | $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = a.fk_soc) 72 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.rowid = a.fk_contact) 73 | LEFT JOIN '.MAIN_DB_PREFIX.'actioncomm_cdav AS ac ON (a.id = ac.fk_object)'; 74 | } 75 | 76 | $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'projet AS p ON (p.rowid = a.fk_project) 77 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON co.rowid = sp.fk_pays 78 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as cos ON cos.rowid = s.fk_pays 79 | WHERE a.id IN (SELECT ar.fk_actioncomm FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar WHERE ar.element_type=\'user\' AND ar.fk_element='.intval($calid).') 80 | AND a.code IN (SELECT cac.code FROM '.MAIN_DB_PREFIX.'c_actioncomm cac WHERE cac.type<>\'systemauto\') 81 | AND a.entity IN ('.getEntity('societe', 1).')'; 82 | if($oid!==false) { 83 | if($ouri===false) 84 | { 85 | $sql.=' AND a.id = '.intval($oid); 86 | } 87 | else 88 | { 89 | $sql.=' AND (a.id = '.intval($oid).' OR ac.uuidext = \''.$this->db->escape($ouri).'\' OR ac.sourceuid = \''.$this->db->escape($ouri).'\')'; 90 | } 91 | } 92 | else 93 | { 94 | $sql.=' AND COALESCE(a.datep2,a.datep)>="'.date('Y-m-d 00:00:00',time()-86400*CDAV_SYNC_PAST).'" 95 | AND a.datep<="'.date('Y-m-d 23:59:59',time()+86400*CDAV_SYNC_FUTURE).'"'; 96 | } 97 | 98 | return $sql; 99 | 100 | } 101 | /** 102 | * Base sql request for project tasks 103 | * 104 | * @param int calendar user id 105 | * @param int task object id 106 | * @param string elem_source 'pt'=Project TODO 'pe'=Project EVENT 107 | * @return string 108 | */ 109 | public function getSqlProjectTasks($calid, $oid=false, $elem_source) 110 | { 111 | global $conf; 112 | 113 | if(!$conf->project->enabled || (isset($conf->global->PROJECT_HIDE_TASKS) && $conf->global->PROJECT_HIDE_TASKS)) 114 | return false; 115 | 116 | if(intval(CDAV_TASK_SYNC)==0 || (intval(CDAV_TASK_SYNC)==1 && $elem_source=='pt')) 117 | return false; 118 | 119 | if(intval(CDAV_TASK_SYNC)==0 || (intval(CDAV_TASK_SYNC)==2 && $elem_source=='pe')) 120 | return false; 121 | 122 | // TODO : replace GROUP_CONCAT by 123 | $sql = 'SELECT 124 | "'.$elem_source.'" elem_source, 125 | pt.rowid AS id, 126 | pt.tms AS lastupd, 127 | pt.*, 128 | p.ref proj_ref, 129 | p.title proj_title, 130 | p.description proj_desc, 131 | s.nom AS soc_nom, 132 | s.address soc_address, 133 | s.zip soc_zip, 134 | s.town soc_town, 135 | cos.label soc_country_label, 136 | s.phone soc_phone, 137 | (SELECT GROUP_CONCAT(u.login) FROM '.MAIN_DB_PREFIX.'element_contact gec 138 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as gtc ON (gtc.rowid=gec.fk_c_type_contact AND gtc.element="project_task" AND gtc.source="internal") 139 | LEFT OUTER JOIN '.MAIN_DB_PREFIX.'user AS u ON (u.rowid=gec.fk_socpeople) 140 | WHERE gec.element_id=pt.rowid AND gtc.element="project_task" AND u.login IS NOT NULL) AS other_users, 141 | (SELECT GROUP_CONCAT(sp.firstname, " ", sp.lastname) FROM '.MAIN_DB_PREFIX.'element_contact gec 142 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as gtc ON (gtc.rowid=gec.fk_c_type_contact AND gtc.element="project_task" AND gtc.source="external") 143 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.rowid=gec.fk_socpeople) 144 | WHERE gec.element_id=pt.rowid AND gtc.element="project_task" AND sp.lastname IS NOT NULL) AS other_contacts 145 | FROM '.MAIN_DB_PREFIX.'projet_task AS pt 146 | LEFT JOIN '.MAIN_DB_PREFIX.'projet AS p ON (p.rowid = pt.fk_projet) 147 | LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = p.fk_soc) 148 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as cos ON cos.rowid = s.fk_pays 149 | LEFT JOIN '.MAIN_DB_PREFIX.'element_contact as ec ON (ec.element_id=pt.rowid) 150 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as tc ON (tc.rowid=ec.fk_c_type_contact AND tc.element="project_task" AND tc.source="internal") 151 | WHERE tc.element="project_task" AND tc.source="internal" AND ec.fk_socpeople='.intval($calid).' 152 | AND pt.entity IN ('.getEntity('societe', 1).')'; 153 | if($oid!==false) 154 | { 155 | $sql.=' AND pt.rowid = '.intval($oid); 156 | } 157 | else 158 | { 159 | $sql.=' AND COALESCE(pt.datee,pt.dateo)>="'.date('Y-m-d 00:00:00',time()-86400*CDAV_SYNC_PAST).'" 160 | AND pt.dateo<="'.date('Y-m-d 23:59:59',time()+86400*CDAV_SYNC_FUTURE).'"'; 161 | } 162 | return $sql; 163 | 164 | } 165 | 166 | /** 167 | * Convert calendar row to VCalendar string 168 | * 169 | * @param row object 170 | * @return string 171 | */ 172 | public function toVCalendar($calid, $obj, $bHeader) 173 | { 174 | if($obj->elem_source=='ev') // Calendar Event 175 | { 176 | $categ = []; 177 | /*if($obj->soc_client) 178 | { 179 | $nick[] = $obj->soc_code_client; 180 | $categ[] = $this->langs->transnoentitiesnoconv('Customer'); 181 | }*/ 182 | 183 | $location=trim(str_replace(array("\r","\t","\n"),' ',$obj->location)); 184 | 185 | // contact address 186 | if(empty($location) && !empty($obj->address)) 187 | { 188 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->address)); 189 | $location = trim($location.', '.$obj->zip); 190 | $location = trim($location.' '.$obj->town); 191 | $location = trim($location.', '.$obj->country_label); 192 | } 193 | 194 | // contact address 195 | if(empty($location) && !empty($obj->soc_address)) 196 | { 197 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->soc_address)); 198 | $location = trim($location.', '.$obj->soc_zip); 199 | $location = trim($location.' '.$obj->soc_town); 200 | $location = trim($location.', '.$obj->soc_country_label); 201 | } 202 | 203 | $address=explode("\n",$obj->address,2); 204 | foreach($address as $kAddr => $vAddr) 205 | { 206 | $address[$kAddr] = trim(str_replace(array("\r","\t"),' ', str_replace("\n",' | ', trim($vAddr)))); 207 | } 208 | $address[]=''; 209 | $address[]=''; 210 | 211 | if($obj->percent==-1 && trim($obj->datep)!='') 212 | $type='VEVENT'; 213 | else 214 | $type='VTODO'; 215 | 216 | $timezone = date_default_timezone_get(); 217 | 218 | $caldata =""; 219 | if($bHeader) 220 | { 221 | $caldata ="BEGIN:VCALENDAR\n"; 222 | $caldata.="VERSION:2.0\n"; 223 | $caldata.="PRODID:-//Dolibarr CDav//FR\n"; 224 | } 225 | $caldata.="BEGIN:".$type."\n"; 226 | $caldata.="CREATED:".gmdate('Ymd\THis', strtotime($obj->datec))."Z\n"; 227 | $caldata.="LAST-MODIFIED:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n"; 228 | $caldata.="DTSTAMP:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n"; 229 | if($obj->sourceuid=='') 230 | $caldata.="UID:".$obj->id.'-ev-'./*$calid.'-cal-'.*/ CDAV_URI_KEY."\n"; 231 | else 232 | $caldata.="UID:".$obj->sourceuid."\n"; 233 | $caldata.="SUMMARY:".strtr(trim($obj->label), array("\n"=>"\\n", "\r"=>""))."\n"; 234 | $caldata.="URL:".dol_buildpath("/comm/action/card.php?id=".$obj->id, 2)."\n"; 235 | $caldata.="LOCATION:".strtr(trim($location), array("\n"=>"\\n", "\r"=>""))."\n"; 236 | $caldata.="PRIORITY:".$obj->priority."\n"; 237 | if($obj->fulldayevent) 238 | { 239 | $caldata.="DTSTART;VALUE=DATE:".date('Ymd', strtotime($obj->datep))."\n"; 240 | if($type=='VEVENT') 241 | { 242 | if(trim($obj->datep2)>trim($obj->datep)) 243 | $caldata.="DTEND;VALUE=DATE:".date('Ymd', strtotime($obj->datep2)+1)."\n"; 244 | else 245 | $caldata.="DTEND;VALUE=DATE:".date('Ymd', strtotime($obj->datep)+(25*3600))."\n"; 246 | } 247 | elseif(trim($obj->datep2)!='') 248 | $caldata.="DUE;VALUE=DATE:".date('Ymd', strtotime($obj->datep2)+1)."\n"; 249 | } 250 | else 251 | { 252 | $caldata.="DTSTART;TZID=".$timezone.":".strtr($obj->datep,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 253 | if($type=='VEVENT') 254 | { 255 | if(trim($obj->datep2)>trim($obj->datep)) 256 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datep2,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 257 | else 258 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datep,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 259 | } 260 | elseif(trim($obj->datep2)!='') 261 | $caldata.="DUE;TZID=".$timezone.":".strtr($obj->datep2,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 262 | } 263 | $caldata.="CLASS:PUBLIC\n"; 264 | if($obj->transparency==1) 265 | $caldata.="TRANSP:TRANSPARENT\n"; 266 | else 267 | $caldata.="TRANSP:OPAQUE\n"; 268 | 269 | if($type=='VEVENT') 270 | $caldata.="STATUS:CONFIRMED\n"; 271 | elseif($obj->percent==0) 272 | $caldata.="STATUS:NEEDS-ACTION\n"; 273 | elseif($obj->percent==100) 274 | $caldata.="STATUS:COMPLETED\n"; 275 | else 276 | { 277 | $caldata.="STATUS:IN-PROCESS\n"; 278 | $caldata.="PERCENT-COMPLETE:".$obj->percent."\n"; 279 | } 280 | 281 | $caldata.="DESCRIPTION:"; 282 | if(!empty($obj->proj_ref)) 283 | $caldata.="💼📋 [".$obj->proj_ref."] ".$obj->proj_title."\\n"; 284 | if(!empty($obj->proj_desc)) 285 | $caldata.="💼⚠️ ".strtr(trim(strip_tags($obj->proj_desc)), array("\n"=>"\\n💼⚠️ ", "\r"=>""))."\\n"; 286 | if(!empty($obj->soc_town)) 287 | $caldata.="💼🏁 ".strtr(trim($obj->soc_town), array("\n"=>"\\n", "\r"=>""))."\\n"; 288 | if(!empty($obj->soc_nom)) 289 | $caldata.="💼🏢 ".strtr(trim($obj->soc_nom), array("\n"=>"\\n", "\r"=>""))."\\n"; 290 | if(!empty($obj->soc_phone)) 291 | $caldata.="💼☎️ ".$obj->soc_phone."\\n"; 292 | if(!empty($obj->firstname) || !empty($obj->lastname)) 293 | $caldata.="💼👨 ".trim($obj->firstname.' '.$obj->lastname)."\\n"; 294 | if(!empty($obj->phone) || !empty($obj->phone_perso) || !empty($obj->phone_mobile)) 295 | $caldata.="💼📞 ".trim($obj->phone.' '.$obj->phone_perso.' '.$obj->phone_mobile)."\\n"; 296 | // removed because unable to swap from one calendar to an other with extrenal client 297 | // if(strpos($obj->other_users,',')) // several 298 | // $caldata.="💼USR: ".$obj->other_users."\\n"; 299 | if($type=='VEVENT') 300 | $caldata.=strtr(trim($obj->note), array("\n"=>"\\n", "\r"=>"")); 301 | else 302 | $caldata.=strtr("\n".trim($obj->note), array("\n- ["=>"\\n[", "\n- "=>"\\n[ ] ", "[x] [ ]"=>"[x]", "[ ] [x]"=>"[x]", "[x] [x]"=>"[x]", "[ ] [ ]"=>"[ ]", "\n"=>"\\n", "\r"=>"")); 303 | $caldata.="\n"; 304 | 305 | $caldata.="END:".$type."\n"; 306 | if($bHeader) 307 | $caldata.="END:VCALENDAR\n"; 308 | } 309 | elseif(substr($obj->elem_source,0,1)=='p') // Project Task pe/pt 310 | { 311 | if($obj->elem_source=='pe') 312 | $type='VEVENT'; 313 | else // 'pt' 314 | $type='VTODO'; 315 | 316 | $location=''; 317 | 318 | // soc address 319 | if(!empty($obj->soc_address)) 320 | { 321 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->soc_address)); 322 | $location = trim($location.', '.$obj->soc_zip); 323 | $location = trim($location.' '.$obj->soc_town); 324 | $location = trim($location.', '.$obj->soc_country_label); 325 | } 326 | 327 | $timezone = date_default_timezone_get(); 328 | 329 | $caldata ="BEGIN:VCALENDAR\n"; 330 | $caldata.="VERSION:2.0\n"; 331 | $caldata.="PRODID:-//Dolibarr CDav//FR\n"; 332 | $caldata.="BEGIN:".$type."\n"; 333 | $caldata.="CREATED:".gmdate('Ymd\THis', strtotime($obj->datec))."Z\n"; 334 | $caldata.="LAST-MODIFIED:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n"; 335 | $caldata.="DTSTAMP:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n"; 336 | $caldata.="UID:".$obj->id.'-'.$obj->elem_source.'-'./*$calid.'-cal-'.*/ CDAV_URI_KEY."\n"; 337 | $caldata.="SUMMARY:[".strtr(trim($obj->proj_title), array("\n"=>"\\n", "\r"=>""))."]".strtr(trim($obj->label), array("\n"=>"\\n", "\r"=>""))."\n"; 338 | $caldata.="URL:".dol_buildpath("/projet/tasks/task.php?id=".$obj->id."&withproject=".$obj->fk_projet,2)."\n"; 339 | $caldata.="LOCATION:".strtr(trim($location), array("\n"=>"\\n", "\r"=>""))."\n"; 340 | $caldata.="PRIORITY:".$obj->priority."\n"; 341 | 342 | $caldata.="DTSTART;TZID=".$timezone.":".strtr($obj->dateo,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 343 | if($type=='VEVENT') 344 | { 345 | if(trim($obj->datee)>trim($obj->dateo)) 346 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datee,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 347 | else 348 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->dateo,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 349 | } 350 | elseif(trim($obj->datee)!='') 351 | $caldata.="DUE;TZID=".$timezone.":".strtr($obj->datee,array(" "=>"T", ":"=>"", "-"=>""))."\n"; 352 | 353 | $caldata.="CLASS:PUBLIC\n"; 354 | $caldata.="TRANSP:OPAQUE\n"; 355 | 356 | if($type=='VEVENT') 357 | $caldata.="STATUS:CONFIRMED\n"; 358 | elseif($obj->progress==0) 359 | $caldata.="STATUS:NEEDS-ACTION\n"; 360 | elseif($obj->progress==100) 361 | $caldata.="STATUS:COMPLETED\n"; 362 | else 363 | { 364 | $caldata.="STATUS:IN-PROCESS\n"; 365 | $caldata.="PERCENT-COMPLETE:".$obj->progress."\n"; 366 | } 367 | 368 | $caldata.="DESCRIPTION:"; 369 | if(!empty($obj->proj_desc)) 370 | $caldata.="💼⚠️ ".strtr(trim(strip_tags($obj->proj_desc)), array("\n"=>"\\n💼⚠️ ", "\r"=>""))."\\n"; 371 | if(!empty($obj->soc_town)) 372 | $caldata.="💼🏁 ".$obj->soc_town."\\n"; 373 | if(!empty($obj->soc_nom)) 374 | $caldata.="💼🏢 ".$obj->soc_nom."\\n"; 375 | if(!empty($obj->soc_phone)) 376 | $caldata.="💼☎️ ".$obj->soc_phone."\\n"; 377 | if(!empty($obj->other_contacts)) 378 | $caldata.="💼👨 ".$obj->other_contacts."\\n"; 379 | if(!empty($obj->proj_ref)) 380 | $caldata.="💼📋 [".$obj->proj_ref."/".$obj->ref."] ".$obj->proj_title."\\n"; 381 | if(!empty($obj->note_public)) 382 | $caldata.="💼📝 ".strtr(trim(strip_tags($obj->note_public)), array("\n"=>"\\n💼📝 ", "\r"=>""))."\\n"; 383 | //removed because unable to swap from one calendar to an other with external client 384 | // if(!empty($obj->note_private)) 385 | // $caldata.="💼🔒 ".strtr(trim(strip_tags($obj->note_private)), array("\n"=>"\\n💼🔒 ", "\r"=>""))."\\n"; 386 | $caldata.=strtr("\n".trim($obj->description), array("\n- ["=>"\\n[", "\n- "=>"\\n[ ] ", "[x] [ ]"=>"[x]", "[ ] [x]"=>"[x]", "[x] [x]"=>"[x]", "[ ] [ ]"=>"[ ]", "\n"=>"\\n", "\r"=>"")); 387 | // removed because unable to swap from one calendar to an other with external client 388 | // if(strpos($obj->other_users,',')) // several 389 | // $caldata.="💼USR: ".$obj->other_users."\\n"; 390 | $caldata.="\n"; 391 | 392 | $caldata.="END:".$type."\n"; 393 | if($bHeader) 394 | $caldata.="END:VCALENDAR\n"; 395 | } 396 | 397 | return $caldata; 398 | } 399 | 400 | public function getFullCalendarObjects($calendarId, $bCalendarData) 401 | { 402 | if(function_exists("debug_log")) 403 | debug_log("getCalendarObjects( $calendarId , $bCalendarData )"); 404 | 405 | $calid = intval($calendarId); 406 | $calevents = [] ; 407 | $rSql = [] ; 408 | 409 | if(! $this->user->rights->agenda->myactions->read) 410 | return $calevents; 411 | 412 | if($calid!=$this->user->id && (!isset($this->user->rights->agenda->allactions->read) || !$this->user->rights->agenda->allactions->read)) 413 | return $calevents; 414 | 415 | $rSql['ev'] = $this->getSqlCalEvents($calid); 416 | $rSql['pe'] = $this->getSqlProjectTasks($calid, false, 'pe'); 417 | $rSql['pt'] = $this->getSqlProjectTasks($calid, false, 'pt'); 418 | 419 | foreach($rSql as $elem_source => $sql) 420 | { 421 | if($sql=='') 422 | continue; 423 | $result = $this->db->query($sql); 424 | 425 | if ($result) 426 | { 427 | while ($obj = $this->db->fetch_object($result)) 428 | { 429 | $calendardata = $this->toVCalendar($calid, $obj, false); 430 | 431 | if($bCalendarData) 432 | { 433 | $calevents[] = [ 434 | 'calendardata' => $calendardata, 435 | 'uri' => $obj->id.'-'.$elem_source.'-'.CDAV_URI_KEY, 436 | 'lastmodified' => strtotime($obj->lastupd), 437 | 'etag' => '"'.md5($calendardata).'"', 438 | 'calendarid' => $calendarId, 439 | 'size' => strlen($calendardata), 440 | 'component' => strpos($calendardata, 'BEGIN:VEVENT')>0 ? 'vevent' : 'vtodo', 441 | ]; 442 | } 443 | else 444 | { 445 | $calevents[] = [ 446 | // 'calendardata' => $calendardata, not necessary because etag+size are present 447 | 'uri' => $obj->id.'-'.$elem_source.'-'.CDAV_URI_KEY, 448 | 'lastmodified' => strtotime($obj->lastupd), 449 | 'etag' => '"'.md5($calendardata).'"', 450 | 'calendarid' => $calendarId, 451 | 'size' => strlen($calendardata), 452 | 'component' => strpos($calendardata, 'BEGIN:VEVENT')>0 ? 'vevent' : 'vtodo', 453 | ]; 454 | } 455 | } 456 | } 457 | } 458 | return $calevents; 459 | } 460 | 461 | } 462 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 1) 52 | { 53 | $_SERVER['PHP_AUTH_USER'] = $rAuth[0]; 54 | $_SERVER['PHP_AUTH_PW'] = $rAuth[1]; 55 | } 56 | } 57 | 58 | // HTTP auth workaround for php in fastcgi mode REDIRECT_HTTP_AUTHORIZATION set by rewrite engine in .htaccess 59 | if( isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && 60 | (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) ) 61 | { 62 | $rAuth = explode(':', base64_decode(substr($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 6))); 63 | 64 | if(count($rAuth)>1) 65 | { 66 | $_SERVER['PHP_AUTH_USER'] = $rAuth[0]; 67 | $_SERVER['PHP_AUTH_PW'] = $rAuth[1]; 68 | } 69 | } 70 | 71 | define('NOTOKENRENEWAL',1); // Disables token renewal 72 | if (! defined('NOLOGIN')) define('NOLOGIN','1'); 73 | if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // We accept to go on this page from external web site. 74 | if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); 75 | if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); 76 | if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); 77 | function llxHeader() { } 78 | function llxFooter() { } 79 | 80 | // Load Dolibarr environment 81 | $res = 0; 82 | // Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) 83 | if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; 84 | // Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME 85 | $tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; 86 | while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } 87 | if (!$res && $i > 0 && @file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; 88 | if (!$res && $i > 0 && @file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; 89 | // Try main.inc.php using relative path 90 | if (!$res && @file_exists("../main.inc.php")) $res = @include "../main.inc.php"; 91 | if (!$res && @file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; 92 | if (!$res && @file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; 93 | if (!$res) die("Include of main fails"); 94 | 95 | if(!defined('DOL_DOCUMENT_ROOT')) 96 | define('DOL_DOCUMENT_ROOT', $dolibarr_main_document_root); 97 | 98 | require DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; // auth method 99 | require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; 100 | 101 | if(!$conf->cdav->enabled) 102 | die('module CDav not enabled !'); 103 | 104 | set_error_handler("exception_error_handler", E_ERROR | E_USER_ERROR | 105 | E_CORE_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR ); 106 | 107 | 108 | require_once './lib/cdav.lib.php'; 109 | 110 | // define CDAV_CONTACT_TAG if not 111 | if(!defined('CDAV_CONTACT_TAG')) 112 | { 113 | if(isset($conf->global->CDAV_CONTACT_TAG)) 114 | define('CDAV_CONTACT_TAG', $conf->global->CDAV_CONTACT_TAG); 115 | else 116 | define('CDAV_CONTACT_TAG', ''); 117 | } 118 | 119 | // define CDAV_URI_KEY if not 120 | if(!defined('CDAV_URI_KEY')) 121 | { 122 | if(isset($conf->global->CDAV_URI_KEY)) 123 | define('CDAV_URI_KEY', $conf->global->CDAV_URI_KEY); 124 | else 125 | define('CDAV_URI_KEY', substr(md5($_SERVER['HTTP_HOST']),0,8)); 126 | } 127 | 128 | // define CDAV_TASK_USER_ROLE if not 129 | if(!defined('CDAV_TASK_USER_ROLE')) 130 | { 131 | if(isset($conf->global->CDAV_TASK_USER_ROLE)) 132 | define('CDAV_TASK_USER_ROLE', $conf->global->CDAV_TASK_USER_ROLE); 133 | else 134 | die('Module CDav is not properly configured : Project user role not set !'); 135 | } 136 | 137 | // define CDAV_SYNC_PAST if not 138 | if(!defined('CDAV_SYNC_PAST')) 139 | { 140 | if(isset($conf->global->CDAV_SYNC_PAST)) 141 | define('CDAV_SYNC_PAST', $conf->global->CDAV_SYNC_PAST); 142 | else 143 | die('Module CDav is not properly configured : Period to sync not set !'); 144 | } 145 | 146 | // define CDAV_SYNC_FUTURE if not 147 | if(!defined('CDAV_SYNC_FUTURE')) 148 | { 149 | if(isset($conf->global->CDAV_SYNC_FUTURE)) 150 | define('CDAV_SYNC_FUTURE', $conf->global->CDAV_SYNC_FUTURE); 151 | else 152 | die('Module CDav is not properly configured : Period to sync not set !'); 153 | } 154 | 155 | // define CDAV_TASK_SYNC if not 156 | if(!defined('CDAV_TASK_SYNC')) 157 | { 158 | if(isset($conf->global->CDAV_TASK_SYNC)) 159 | define('CDAV_TASK_SYNC', $conf->global->CDAV_TASK_SYNC); 160 | else 161 | define('CDAV_TASK_SYNC', '0'); 162 | } 163 | 164 | // define CDAV_THIRD_SYNC if not 165 | if(!defined('CDAV_THIRD_SYNC')) 166 | { 167 | if(isset($conf->global->CDAV_THIRD_SYNC)) 168 | define('CDAV_THIRD_SYNC', $conf->global->CDAV_THIRD_SYNC); 169 | else 170 | define('CDAV_THIRD_SYNC', '0'); 171 | } 172 | 173 | // define CDAV_MEMBER_SYNC if not 174 | if(!defined('CDAV_MEMBER_SYNC')) 175 | { 176 | if(isset($conf->global->CDAV_MEMBER_SYNC)) 177 | define('CDAV_MEMBER_SYNC', $conf->global->CDAV_MEMBER_SYNC); 178 | else 179 | define('CDAV_MEMBER_SYNC', '0'); 180 | } 181 | 182 | // 0 < CDAV_ADDRESSBOOK_ID_SHIFT = Contacts 183 | // CDAV_ADDRESSBOOK_ID_SHIFT < 2*CDAV_ADDRESSBOOK_ID_SHIFT = Thirdparties 184 | // 2*CDAV_ADDRESSBOOK_ID_SHIFT < 3*CDAV_ADDRESSBOOK_ID_SHIFT = Members 185 | define('CDAV_ADDRESSBOOK_ID_SHIFT', 100000); 186 | 187 | // Sabre/dav configuration 188 | 189 | use Sabre\DAV; 190 | use Sabre\DAVACL; 191 | 192 | // The autoloader 193 | require DOL_DOCUMENT_ROOT.'/includes/sabre/autoload.php'; 194 | require './class/PrincipalsDolibarr.php'; 195 | require './class/CardDAVDolibarr.php'; 196 | require './class/CalDAVDolibarr.php'; 197 | 198 | $user = new User($db); 199 | 200 | if(isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER']!='') 201 | { 202 | $user->fetch('',$_SERVER['PHP_AUTH_USER']); 203 | $user->getrights(); 204 | } 205 | 206 | $cdavLib = new CdavLib($user, $db, $langs); 207 | 208 | // Authentication 209 | $authBackend = new DAV\Auth\Backend\BasicCallBack(function ($username, $password) 210 | { 211 | global $user; 212 | global $conf; 213 | global $dolibarr_main_authentication; 214 | 215 | 216 | if ( ! isset($user->login) || $user->login=='') 217 | { 218 | debug_log("Authentication failed 1 for user $username with pass ".str_pad('', strlen($password), '*')); 219 | return false; 220 | } 221 | if (!empty($user->societe_id) || !empty($user->socid)) // external user 222 | { 223 | debug_log("Authentication failed 2 for user $username with pass ".str_pad('', strlen($password), '*')); 224 | return false; 225 | } 226 | if ($user->login!=$username) 227 | { 228 | debug_log("Authentication failed 3 for user $username with pass ".str_pad('', strlen($password), '*')); 229 | return false; 230 | } 231 | /*if ($user->pass_indatabase_crypted == '' || dol_hash($password) != $user->pass_indatabase_crypted) 232 | return false;*/ 233 | 234 | // Authentication mode 235 | // disable googlerecaptcha 236 | $dolibarr_main_authentication = str_replace('googlerecaptcha','dolibarr', $dolibarr_main_authentication); 237 | if (empty($dolibarr_main_authentication)) 238 | $dolibarr_main_authentication='http,dolibarr'; 239 | $authmode = explode(',',$dolibarr_main_authentication); 240 | $entity = (GETPOST('entity','int') ? GETPOST('entity','int') : (!empty($conf->entity) ? $conf->entity : 1)); 241 | if( ((float) DOL_VERSION < 11.0) && checkLoginPassEntity($username,$password,$entity,$authmode)!=$username 242 | || 243 | ((float) DOL_VERSION >= 11.0) && checkLoginPassEntity($username,$password,$entity,$authmode,'dav')!=$username ) 244 | { 245 | debug_log("Authentication failed 4 for user $username with pass ".str_pad('', strlen($password), '*')); 246 | return false; 247 | } 248 | debug_log("Authentication OK for user $username "); 249 | return true; 250 | }); 251 | 252 | $authBackend->setRealm('Dolibarr'); 253 | 254 | // The lock manager is reponsible for making sure users don't overwrite 255 | // each others changes. 256 | $lockBackend = new DAV\Locks\Backend\File($dolibarr_main_data_root.'/cdav/.locks'); 257 | 258 | // Principals Backend 259 | $principalBackend = new DAVACL\PrincipalBackend\Dolibarr($user,$db); 260 | 261 | // CardDav & CalDav Backend 262 | $carddavBackend = new Sabre\CardDAV\Backend\Dolibarr($user,$db,$langs); 263 | $caldavBackend = new Sabre\CalDAV\Backend\Dolibarr($user,$db,$langs, $cdavLib); 264 | 265 | // Setting up the directory tree // 266 | $nodes = array( 267 | // /principals 268 | new DAVACL\PrincipalCollection($principalBackend), 269 | // /addressbook 270 | new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend), 271 | // /calendars 272 | new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend), 273 | // / Public docs 274 | new DAV\FS\Directory($dolibarr_main_data_root. '/cdav/public') 275 | ); 276 | // admin can access all dolibarr documents 277 | if($user->admin) 278 | $nodes[] = new DAV\FS\Directory($dolibarr_main_data_root); 279 | 280 | // The server object is responsible for making sense out of the WebDAV protocol 281 | $server = new DAV\Server($nodes); 282 | 283 | // If your server is not on your webroot, make sure the following line has the 284 | // correct information 285 | $server->setBaseUri(dol_buildpath('cdav/server.php', 1).'/'); 286 | 287 | 288 | $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend)); 289 | $server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend)); 290 | $server->addPlugin(new \Sabre\DAV\Browser\Plugin()); 291 | $server->addPlugin(new \Sabre\CardDAV\Plugin()); 292 | $server->addPlugin(new \Sabre\CalDAV\Plugin()); 293 | $DAVACL_plugin = new \Sabre\DAVACL\Plugin(); 294 | $DAVACL_plugin->allowUnauthenticatedAccess = false; 295 | $server->addPlugin($DAVACL_plugin); 296 | 297 | debug_log("Ready : ".$user->login); 298 | 299 | // All we need to do now, is to fire up the server 300 | $server->exec(); 301 | 302 | if (is_object($db)) $db->close(); 303 | -------------------------------------------------------------------------------- /sql/llx_actioncomm_cdav.sql: -------------------------------------------------------------------------------- 1 | -- ============================================================================ 2 | -- Copyright (C) 2015 Jérôme ANDANSON 3 | -- 4 | -- This program is free software; you can redistribute it and/or modify 5 | -- it under the terms of the GNU General Public License as published by 6 | -- the Free Software Foundation; either version 3 of the License, or 7 | -- (at your option) any later version. 8 | -- 9 | -- This program is distributed in the hope that it will be useful, 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | -- GNU General Public License for more details. 13 | -- 14 | -- You should have received a copy of the GNU General Public License 15 | -- along with this program. If not, see . 16 | -- 17 | -- Table of "actioncomm_cdav" for cdav module 18 | -- ============================================================================ 19 | 20 | CREATE TABLE IF NOT EXISTS `llx_actioncomm_cdav` ( 21 | `fk_object` int(11) NOT NULL, 22 | `uuidext` varchar(255) NOT NULL, 23 | `sourceuid` varchar(255) NOT NULL, 24 | PRIMARY KEY (`fk_object`), 25 | KEY `uuidext` (`uuidext`) 26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Storage of external UUID created by externals applications'; 27 | -------------------------------------------------------------------------------- /sql/update_001.sql: -------------------------------------------------------------------------------- 1 | -- ============================================================================ 2 | -- Copyright (C) 2017 Jean-Pierre Morfin 3 | -- 4 | -- This program is free software; you can redistribute it and/or modify 5 | -- it under the terms of the GNU General Public License as published by 6 | -- the Free Software Foundation; either version 3 of the License, or 7 | -- (at your option) any later version. 8 | -- 9 | -- This program is distributed in the hope that it will be useful, 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | -- GNU General Public License for more details. 13 | -- 14 | -- You should have received a copy of the GNU General Public License 15 | -- along with this program. If not, see . 16 | -- 17 | -- add column sourceuid for cdav module 18 | -- ============================================================================ 19 | 20 | ALTER TABLE `llx_actioncomm_cdav` ADD `sourceuid` VARCHAR(255) NOT NULL AFTER `uuidext`; 21 | --------------------------------------------------------------------------------