Codebase list cyrus-imapd / debian/3.2.2-1 imap / http_dav.h
debian/3.2.2-1

Tree @debian/3.2.2-1 (Download .tar.gz)

http_dav.h @debian/3.2.2-1raw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
/* http_dav.h -- Routines for dealing with DAV properties in httpd
 *
 * Copyright (c) 1994-2011 Carnegie Mellon University.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The name "Carnegie Mellon University" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For permission or any legal
 *    details, please contact
 *      Carnegie Mellon University
 *      Center for Technology Transfer and Enterprise Creation
 *      4615 Forbes Avenue
 *      Suite 302
 *      Pittsburgh, PA  15213
 *      (412) 268-7393, fax: (412) 268-7395
 *      innovation@andrew.cmu.edu
 *
 * 4. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by Computing Services
 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 *
 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef HTTP_DAV_H
#define HTTP_DAV_H

#include <stdint.h>
#include <libical/ical.h>
#include <libxml/tree.h>

#include "acl.h"
#include "annotate.h"
#include "caldav_db.h"
#include "httpd.h"
#include "spool.h"
#include "quota.h"
#include "strarray.h"

#define NULL_ETAG       "da39a3ee5e6b4b0d3255bfef95601890afd80709"
                        /* SHA1("") */

#define SERVER_INFO     ".server-info"
#define SCHED_INBOX     "Inbox/"
#define SCHED_OUTBOX    "Outbox/"
#define SCHED_DEFAULT   "Default/"
#define MANAGED_ATTACH  "Attachments/"

/* XML namespace URIs */
#define XML_NS_DAV      "DAV:"
#define XML_NS_CALDAV   "urn:ietf:params:xml:ns:caldav"
#define XML_NS_CARDDAV  "urn:ietf:params:xml:ns:carddav"
#define XML_NS_ISCHED   "urn:ietf:params:xml:ns:ischedule"
#define XML_NS_CS       "http://calendarserver.org/ns/"
#define XML_NS_MECOM    "http://me.com/_namespace/"
#define XML_NS_MOBME    "urn:mobileme:davservices"
#define XML_NS_APPLE    "http://apple.com/ns/ical/"
#define XML_NS_USERFLAG "http://cyrusimap.org/ns/userflag/"
#define XML_NS_SYSFLAG  "http://cyrusimap.org/ns/sysflag/"
#define XML_NS_DAVMOUNT "http://purl.org/NET/webdav/mount/"

#define USER_COLLECTION_PREFIX  "user"
#define GROUP_COLLECTION_PREFIX "group"

#define LOCK_TOKEN_URL_SCHEME "urn:uuid:"
#define SYNC_TOKEN_URL_SCHEME "data:,"

#define SHARED_COLLECTION_DELIM '.'

/* Index into known namespace array */
enum {
    NS_REQ_ROOT = -1,   /* special case: ns of request root (not an index) */
    NS_DAV,
    NS_CALDAV,
    NS_CARDDAV,
    NS_ISCHED,
    NS_CS,
    NS_MECOM,
    NS_MOBME,
    NS_CYRUS,
};
#define NUM_NAMESPACE 8

/* Cyrus-specific privileges */
#define DACL_PROPCOL    ACL_WRITE       /* CY:write-properties-collection */
#define DACL_PROPRSRC   ACL_ANNOTATEMSG /* CY:write-properties-resource */
#define DACL_MKCOL      ACL_CREATE      /* CY:make-collection */
#define DACL_ADDRSRC    ACL_POST        /* CY:add-resource */
#define DACL_RMCOL      ACL_DELETEMBOX  /* CY:remove-collection */
#define DACL_RMRSRC     (ACL_DELETEMSG\
                         |ACL_EXPUNGE)  /* CY:remove-resource */
#define DACL_ADMIN      ACL_ADMIN       /* CY:admin (aggregates
                                           DAV:read-acl, DAV:write-acl,
                                           DAV:unlock and DAV:share) */

/* WebDAV (RFC 3744) privileges */
#define DACL_READ       (ACL_READ\
                         |ACL_LOOKUP)   /* DAV:read (aggregates
                                           DAV:read-current-user-privilege-set
                                           and CALDAV:read-free-busy) */
#define DACL_WRITECONT  ACL_INSERT      /* DAV:write-content */
#define DACL_WRITEPROPS (DACL_PROPCOL\
                         |DACL_PROPRSRC)/* DAV:write-properties */
#define DACL_BIND       (DACL_MKCOL\
                         |DACL_ADDRSRC) /* DAV:bind */
#define DACL_UNBIND     (DACL_RMCOL\
                         |DACL_RMRSRC)  /* DAV:unbind */
#define DACL_WRITE      (DACL_WRITECONT\
                         |DACL_WRITEPROPS\
                         |DACL_BIND\
                         |DACL_UNBIND)  /* DAV:write */
#define DACL_ALL        (DACL_READ\
                         |DACL_WRITE\
                         |DACL_ADMIN)   /* DAV:all */

/* CalDAV (RFC 4791) privileges */
#define DACL_READFB     ACL_USER9       /* CALDAV:read-free-busy
                                           (implicit if user has DAV:read) */

/* CalDAV Scheduling (RFC 6638) privileges

   We use the same ACLs for both schedule-deliver* and schedule-send* because
   functionality of Scheduling Inbox and Outbox are mutually exclusive.
   We use ACL_USER9 for both read-free-busy and schedule-*-freebusy because
   Scheduling Inbox and Outbox don't contribute to free-busy.
*/
#define DACL_SCHEDFB    ACL_USER9       /* For Scheduling Inbox:
                                           CALDAV:schedule-query-freebusy

                                           For Scheduling Outbox:
                                           CALDAV:schedule-send-freebusy */
#define DACL_INVITE     ACL_USER8       /* For Scheduling Inbox:
                                           CALDAV:schedule-deliver-invite

                                           For Scheduling Outbox:
                                           CALDAV:schedule-send-invite */
#define DACL_REPLY      ACL_USER7       /* For Scheduling Inbox:
                                           CALDAV:schedule-deliver-reply

                                           For Scheduling Outbox:
                                           CALDAV:schedule-send-reply */
#define DACL_SCHED      (DACL_SCHEDFB\
                         |DACL_INVITE\
                         |DACL_REPLY)   /* For Scheduling Inbox:
                                           CALDAV:schedule-deliver (aggregates
                                           CALDAV:schedule-deliver-invite,
                                           schedule-deliver-reply,
                                           schedule-query-freebusy);

                                           For Scheduling Outbox:
                                           CALDAV:schedule-send (aggregates
                                           CALDAV:schedule-send-invite,
                                           schedule-send-reply,
                                           schedule-send-freebusy) */

/* Index into preconditions array */
enum {
    /* WebDAV (RFC 4918) preconditions */
    DAV_PROT_PROP = 1,
    DAV_BAD_LOCK_TOKEN,
    DAV_NEED_LOCK_TOKEN,
    DAV_LOCKED,
    DAV_FINITE_DEPTH,

    /* WebDAV Versioning (RFC 3253) preconditions */
    DAV_SUPP_REPORT,
    DAV_RES_EXISTS,

    /* WebDAV ACL (RFC 3744) preconditions */
    DAV_NEED_PRIVS,
    DAV_NO_INVERT,
    DAV_NO_ABSTRACT,
    DAV_SUPP_PRIV,
    DAV_RECOG_PRINC,
    DAV_ALLOW_PRINC,
    DAV_GRANT_ONLY,

    /* WebDAV Quota (RFC 4331) preconditions */
    DAV_OVER_QUOTA,
    DAV_NO_DISK_SPACE,

    /* WebDAV Extended MKCOL (RFC 5689) preconditions */
    DAV_VALID_RESTYPE,

    /* WebDAV Sync (RFC 6578) preconditions */
    DAV_SYNC_TOKEN,
    DAV_OVER_LIMIT,

    /* CalDAV (RFC 4791) preconditions */
    CALDAV_SUPP_DATA,
    CALDAV_VALID_DATA,
    CALDAV_VALID_OBJECT,
    CALDAV_SUPP_COMP,
    CALDAV_LOCATION_OK,
    CALDAV_UID_CONFLICT,
    CALDAV_SUPP_FILTER,
    CALDAV_VALID_FILTER,
    CALDAV_SUPP_COLLATION,

    /* RSCALE (RFC 7529) preconditions */
    CALDAV_SUPP_RSCALE,

    /* Time Zones by Reference (RFC 7809) preconditions */
    CALDAV_VALID_TIMEZONE,

    /* Managed Attachments (draft-ietf-calext-caldav-attachments) preconditions */
    CALDAV_VALID_MANAGEDID,

    /* Bulk Change (draft-daboo-calendarserver-bulk-change) preconditions */
    CALDAV_CTAG_OK,

    /* CalDAV Scheduling (RFC 6638) preconditions */
    CALDAV_VALID_SCHED,
    CALDAV_VALID_ORGANIZER,
    CALDAV_UNIQUE_OBJECT,
    CALDAV_SAME_ORGANIZER,
    CALDAV_ALLOWED_ORG_CHANGE,
    CALDAV_ALLOWED_ATT_CHANGE,

    /* iSchedule (draft-desruisseaux-ischedule) preconditions */
    ISCHED_UNSUPP_VERSION,
    ISCHED_UNSUPP_DATA,
    ISCHED_INVALID_DATA,
    ISCHED_INVALID_SCHED,
    ISCHED_ORIG_MISSING,
    ISCHED_MULTIPLE_ORIG,
    ISCHED_ORIG_INVALID,
    ISCHED_ORIG_DENIED,
    ISCHED_RECIP_MISSING,
    ISCHED_RECIP_MISMATCH,
    ISCHED_VERIFICATION_FAILED,

    /* CardDAV (RFC 6352) preconditions */
    CARDDAV_SUPP_DATA,
    CARDDAV_VALID_DATA,
    CARDDAV_UID_CONFLICT,
    CARDDAV_LOCATION_OK,
    CARDDAV_SUPP_FILTER,
    CARDDAV_SUPP_COLLATION
};

/* Preference bits */
enum {
    PREFER_MIN    = (1<<0),
    PREFER_REP    = (1<<1),
    PREFER_NOROOT = (1<<2)
};

#define NO_DUP_CHECK (1<<7)

/* PROPFIND modes */
enum {
    PROPFIND_NONE = 0,                  /* only used with REPORT */
    PROPFIND_ALL,
    PROPFIND_NAME,
    PROPFIND_PROP,
    PROPFIND_EXPAND                     /* only used with expand-prop REPORT */
};


extern struct meth_params princ_params;

/* Function to fetch resource validators */
typedef int (*get_validators_t)(struct mailbox *mailbox, void *data,
                                const char *userid, struct index_record *record,
                                const char **etag, time_t *lastmod);

/* Function to fetch resource modseq */
typedef modseq_t (*get_modseq_t)(struct mailbox *mailbox,
                                 void *data, const char *userid);

typedef void *(*db_open_proc_t)(struct mailbox *mailbox);
typedef int (*db_close_proc_t)(void *davdb);

/* Function to lookup DAV 'resource' in 'mailbox',
 * placing the record in 'data'
 */
typedef int (*db_lookup_proc_t)(void *davdb, const char *mailbox,
                                const char *resource, void **data,
                                int tombstones);

/* Function to lookup DAV 'imapuid' in 'mailbox',
 * placing the record in 'data'
 */
typedef int (*db_imapuid_proc_t)(void *davdb, const char *mailbox,
                                 int uid, void **data, int tombstones);

/* Function to process each DAV resource in 'mailbox' with 'cb' */
typedef int (*db_foreach_proc_t)(void *davdb, const char *mailbox,
                                 int (*cb)(void *rock, void *data), void *rock);

/* Function to process 'limit' DAV resources
   updated since 'oldmodseq' in 'mailbox' with 'cb' */
typedef int (*db_updates_proc_t)(void *davdb, modseq_t oldmodseq,
                                 const char *mailbox, int kind, int limit,
                                 int (*cb)(void *rock, void *data), void *rock);

/* Context for fetching properties */
struct propfind_entry_list;
struct prop_entry;
struct error_t;

/* Propfind return flags */
struct fctx_flags_t {
    unsigned long fetcheddata : 1;      /* Did we fetch iCalendar/vCard data? */
    unsigned long cs_sharing  : 1;      /* Is client using CS sharing? */
};

struct propfind_ctx {
    struct transaction_t *txn;          /* request transaction */
    struct request_target_t *req_tgt;   /* parsed target URL */
    unsigned mode;                      /* none, allprop, propname, prop */
    unsigned depth;                     /* 0 = root, 1 = calendar, 2 = resrc */
    unsigned prefer;                    /* bitmask of client preferences */
    const char *userid;                 /* userid client has logged in as */
    int userisadmin;                    /* is userid an admin */
    struct auth_state *authstate;       /* authorization state for userid */
    void *davdb;                        /* DAV DB corresponding to collection */
    const mbentry_t *mbentry;           /* mbentry corresponding to collection */
    struct mailbox *mailbox;            /* mailbox corresponding to collection */
    struct quota quota;                 /* quota info for collection */
    struct index_record *record;        /* cyrus.index record for resource */
    void *data;                         /* DAV record for resource */
    get_validators_t get_validators;    /* fetch resource validators */
    struct buf msg_buf;                 /* mmap()'d resource file */
    void *obj;                          /* parsed resource */
    void (*free_obj)(void *);           /* free parsed object */
    unsigned long reqd_privs;           /* privileges req'd on collections */
    int (*filter)(struct propfind_ctx *,
                  void *data);          /* callback to filter resources */
    void *filter_crit;                  /* criteria to filter resources */
    db_open_proc_t open_db;             /* open DAV DB for a given mailbox */
    db_close_proc_t close_db;           /* close DAV DB for a given mailbox */
    db_lookup_proc_t lookup_resource;   /* lookup a specific resource */
    db_foreach_proc_t foreach_resource; /* process all resources in a mailbox */
    int (*proc_by_resource)(void *rock, /* Callback to process a resource */
                            void *data);
    struct propfind_entry_list *elist;  /* List of props to fetch w/callbacks */
    const struct prop_entry *lprops;    /* Array of known "live" properties */
    xmlNodePtr root;                    /* root node to add to XML tree */
    xmlNsPtr *ns;                       /* Array of our known namespaces */
    struct hash_table *ns_table;        /* Table of all ns attached to resp */
    unsigned prefix_count;              /* Count of new ns added to resp */
    int *ret;                           /* Return code to pass up to caller */
    struct fctx_flags_t flags;          /* Return flags for this propfind */
    struct buf buf;                     /* Working buffer */
    xmlBufferPtr xmlbuf;                /* Buffer for dumping XML nodes */
};


/* Context for patching (writing) properties */
struct proppatch_ctx {
    struct transaction_t *txn;          /* request transaction */
    struct mailbox *mailbox;            /* mailbox related to the collection */
    struct index_record *record;        /* record of the specific resource */
    const struct prop_entry *lprops;    /* Array of known "live" properties */
    xmlNodePtr root;                    /* root node to add to XML tree */
    xmlNsPtr *ns;                       /* Array of our supported namespaces */
    struct txn *tid;                    /* Transaction ID for annot writes */
    int *ret;                           /* Return code to pass up to caller */
    struct buf buf;                     /* Working buffer */
};


/* Structure for property status */
struct propstat {
    xmlNodePtr root;
    long status;
    unsigned precond;
};

/* Index into propstat array */
enum {
    PROPSTAT_OK = 0,
    PROPSTAT_UNAUTH,
    PROPSTAT_FORBID,
    PROPSTAT_NOTFOUND,
    PROPSTAT_CONFLICT,
    PROPSTAT_FAILEDDEP,
    PROPSTAT_ERROR,
    PROPSTAT_OVERQUOTA
};
#define NUM_PROPSTAT 8


/* Context for "live" properties */
struct prop_entry {
    const char *name;                   /* Property name */
    unsigned ns;                        /* Property namespace */
    unsigned char flags;                /* Flags for how/where props apply */
    int (*get)(const xmlChar *name,     /* Callback to fetch property */
               xmlNsPtr ns, struct propfind_ctx *fctx, xmlNodePtr prop,
               xmlNodePtr resp, struct propstat *propstat, void *rock);
    int (*put)(xmlNodePtr prop,         /* Callback to write property */
               unsigned set, struct proppatch_ctx *pctx,
               struct propstat *propstat, void *rock);
    void *rock;                         /* Add'l data to pass to callback */
};

/* Bitmask of property flags */
enum {
    PROP_ALLPROP =      (1<<0),         /* Returned in <allprop> request */
    PROP_COLLECTION =   (1<<1),         /* Returned for collection */
    PROP_RESOURCE =     (1<<2),         /* Returned for resource */
    PROP_PERUSER =      (1<<3),         /* Per-user property */
    PROP_PRESCREEN =    (1<<4),         /* Prescreen property using callback */
    PROP_CLEANUP =      (1<<5)          /* Cleanup property using callback */
};


/* Function to check headers for preconditions */
struct meth_params;
typedef int (*check_precond_t)(struct transaction_t *txn,
                               struct meth_params *params,
                               struct mailbox *mailbox, const void *data,
                               const char *etag, time_t lastmod);

/* Function to insert/update DAV resource in 'data' */
typedef int (*db_write_proc_t)(void *davdb, void *data);

/* Function to delete resource in 'rowid' */
typedef int (*db_delete_proc_t)(void *davdb, unsigned rowid);

typedef int (*db_proc_t)(void *davdb);

struct davdb_params {
    db_open_proc_t open_db;             /* open DAV DB for a given mailbox */
    db_close_proc_t close_db;           /* close DAV DB for a given mailbox */
    db_proc_t begin_transaction;
    db_proc_t commit_transaction;
    db_proc_t abort_transaction;
    db_lookup_proc_t lookup_resource;   /* lookup a specific resource */
    db_imapuid_proc_t lookup_imapuid;   /* lookup a specific resource */
    db_foreach_proc_t foreach_resource; /* process all resources in a mailbox */
    db_updates_proc_t foreach_update;   /* process updated resources in a mbox */
    /* XXX - convert these to lock management only.  For everything else,
     * we need to go via mailbox.c for replication support */
    db_write_proc_t write_resourceLOCKONLY;     /* write a specific resource */
    db_delete_proc_t delete_resourceLOCKONLY;   /* delete a specific resource */
};

/*
 * Process 'priv', augmenting 'rights' as necessary.
 * Returns 1 if processing is complete.
 * Returns 0 if processing should continue in meth_acl()
 */
typedef int (*acl_proc_t)(struct transaction_t *txn, xmlNodePtr priv,
                          int *rights);

/* Function to do special processing for DELETE method (optional) */
typedef int (*delete_proc_t)(struct transaction_t *txn, struct mailbox *mailbox,
                             struct index_record *record, void *data);

/* Function to do special processing for GET method (optional) */
typedef int (*get_proc_t)(struct transaction_t *txn, struct mailbox *mailbox,
                          struct index_record *record, void *data, void **obj);

/* Function to convert to/from MIME type */
struct mime_type_t {
    const char *content_type;
    const char *version;
    const char *file_ext;
    struct buf* (*from_object)(void *);
    void* (*to_object)(const struct buf *);
    void (*free)(void *);
    const char* (*begin_stream)(struct buf *, struct mailbox *mailbox,
                                const char *prodid, const char *name,
                                const char *desc, const char *color);
    void (*end_stream)(struct buf *);
};

/* meth_mkcol() parameters */
typedef int (*mkcol_proc_t)(struct mailbox *mailbox);

struct mkcol_params {
    unsigned location_precond;          /* precond code for bad location */
    uint32_t mbtype;                    /* mailbox type collection */
    mkcol_proc_t proc;                  /* func to do post-create processing */
};

/*
 * Function to do special processing for POST method (optional).
 * Returns HTTP_CONTINUE if processing should continue in meth_post(),
 * otherwise processing is complete.
 */
typedef int (*post_proc_t)(struct transaction_t *txn);

typedef int (*import_proc_t)(struct transaction_t *txn, void *obj,
                             struct mailbox *mailbox, void *davdb,
                             xmlNodePtr root, xmlNsPtr *ns, unsigned flags);

/* POST "mode" bits */
enum {
    POST_ADDMEMBER = (1<<0),
    POST_SHARE     = (1<<1)
};

/* meth_put() parameters */
typedef int (*put_proc_t)(struct transaction_t *txn, void *obj,
                          struct mailbox *mailbox, const char *resource,
                          void *davdb, unsigned flags);

struct copy_params {
    unsigned uid_conf_precond;          /* precond code for UID conflict */
    put_proc_t proc;                    /* function to process & COPY a rsrc */
};

struct post_params {
    unsigned allowed;                   /* allowed generic POST "modes" */
    post_proc_t proc;                   /* special POST handling (optional) */
    struct {
        unsigned data_ns;               /* namespace of "data" property */
        const char *data_prop;          /* name of "data" prop for CRUD (opt) */
        import_proc_t import;           /* func to import multiple rsrcs (opt) */
    } bulk;
};

struct put_params {
    unsigned supp_data_precond;         /* precond code for unsupported data */
    put_proc_t proc;                    /* function to process & PUT a rsrc */
};

struct propfind_params {
    unsigned finite_depth_precond;      /* precond code for finite depth */
    const struct prop_entry *lprops;    /* array of "live" properties */
};

/* meth_report() parameters */
typedef int (*report_proc_t)(struct transaction_t *txn,
                             struct meth_params *rparams,
                             xmlNodePtr inroot, struct propfind_ctx *fctx);

struct report_type_t {
    const char *name;                   /* report name */
    unsigned ns;                        /* report namespace */
    const char *resp_root;              /* name of XML root element in resp */
    report_proc_t proc;                 /* function to generate the report */
    unsigned long reqd_privs;           /* privileges required to run report */
    unsigned flags;                     /* report-specific flags */
};

/* Report flags */
enum {
    REPORT_NEED_MBOX    = (1<<0),
    REPORT_NEED_PROPS   = (1<<1),
    REPORT_ALLOW_PROPS  = (1<<2),
    REPORT_DEPTH_ZERO   = (1<<3)
};

/* Overwrite flags */
enum {
    OVERWRITE_NO = 0,
    OVERWRITE_YES
};

struct meth_params {
    struct mime_type_t *mime_types;     /* array of MIME types and conv funcs */
    parse_path_t parse_path;            /* parse URI path & generate mboxname */
    get_validators_t get_validators;    /* fetch resource validators */
    get_modseq_t get_modseq;            /* fetch resource modseq */
    check_precond_t check_precond;      /* check headers for preconditions */
    struct davdb_params davdb;          /* DAV DB access functions */
    acl_proc_t acl_ext;                 /* special ACL handling (extensions) */
    struct copy_params copy;            /* params for copying a resource */
    delete_proc_t delete;               /* special DELETE handling (optional) */
    get_proc_t get;                     /* special GET handling (optional) */
    struct mkcol_params mkcol;          /* params for creating new collection */
    struct patch_doc_t *patch_docs;     /* array of patch docs & funcs (opt) */
    struct post_params post;            /* params for POST handling */
    struct put_params put;              /* params for putting a resource */
    struct propfind_params propfind;    /* params for finding properties */
    const struct report_type_t *reports;/* array of reports & proc functions */
};

extern struct meth_params webdav_params;

enum {
    MATCH_TYPE_CONTAINS = 0,
    MATCH_TYPE_EQUALS,
    MATCH_TYPE_PREFIX,
    MATCH_TYPE_SUFFIX
};

struct match_type_t {
    const char *name;
    unsigned value;
};

extern const struct match_type_t dav_match_types[];

enum {
    COLLATION_UNICODE = 0,
    COLLATION_ASCII,
    COLLATION_OCTET
};

struct collation_t {
    const char *name;
    unsigned value;
};

extern const struct collation_t dav_collations[];
    
struct text_match_t {
    xmlChar *text;
    unsigned negate    : 1;
    unsigned type      : 3;
    unsigned collation : 3;
    struct text_match_t *next;
};

struct param_filter {
    xmlChar *name;
    unsigned kind;
    unsigned not_defined : 1;
    struct text_match_t *match;
    struct param_filter *next;
};

struct prop_filter {
    xmlChar *name;
    unsigned kind;
    unsigned allof       : 1;
    unsigned not_defined : 1;
    void *other;                /* some other filter defined by caller */
    struct text_match_t *match;
    struct param_filter *param;
    struct prop_filter *next;
};

struct filter_profile_t {
    unsigned allof      : 1;
    unsigned collation  : 3;
    unsigned filter_precond;
    unsigned collation_precond;
    unsigned (*prop_string_to_kind)(const char *);
    unsigned no_prop_value;
    unsigned (*param_string_to_kind)(const char *);
    unsigned no_param_value;
    void (*parse_propfilter)(xmlNodePtr, struct prop_filter *,
                             struct error_t *);
};

#define DAV_FILTER_ISNOTDEF_ERR \
    "is-not-defined can NOT be combined with other elements"

void dav_get_synctoken(struct mailbox *mailbox,
                       struct buf *buf, const char *prefix);

void dav_parse_propfilter(xmlNodePtr root, struct prop_filter **prop,
                          struct filter_profile_t *profile,
                          struct error_t *error);
void dav_free_propfilter(struct prop_filter *prop);
int dav_apply_textmatch(xmlChar *text, struct text_match_t *match);

int report_expand_prop(struct transaction_t *txn, struct meth_params *rparams,
                       xmlNodePtr inroot, struct propfind_ctx *fctx);
int report_acl_prin_prop(struct transaction_t *txn, struct meth_params *rparams,
                         xmlNodePtr inroot, struct propfind_ctx *fctx);
int report_multiget(struct transaction_t *txn, struct meth_params *rparams,
                    xmlNodePtr inroot, struct propfind_ctx *fctx);
int report_sync_col(struct transaction_t *txn, struct meth_params *rparams,
                    xmlNodePtr inroot, struct propfind_ctx *fctx);


unsigned long calcarddav_allow_cb(struct request_target_t *tgt);
int dav_parse_req_target(struct transaction_t *txn,
                         struct meth_params *params);
int calcarddav_parse_path(const char *path, struct request_target_t *tgt,
                          const char *mboxprefix, const char **resultstr);
int dav_get_validators(struct mailbox *mailbox, void *data,
                       const char *userid, struct index_record *record,
                       const char **etag, time_t *lastmod);
modseq_t dav_get_modseq(struct mailbox *mailbox,
                        void *data, const char *userid);
int dav_check_precond(struct transaction_t *txn, struct meth_params *params,
                      struct mailbox *mailbox, const void *data,
                      const char *etag, time_t lastmod);
int dav_store_resource(struct transaction_t *txn,
                       const char *data, size_t datalen,
                       struct mailbox *mailbox, struct index_record *oldrecord,
                       modseq_t createdmodseq, strarray_t *imapflags);
int dav_premethod(struct transaction_t *txn);
unsigned get_preferences(struct transaction_t *txn);
struct mime_type_t *get_accept_type(const char **hdr, struct mime_type_t *types);

int parse_xml_body(struct transaction_t *txn, xmlNodePtr *root,
                   const char *mimetype);

size_t make_collection_url(struct buf *buf, const char *urlprefix, int haszzzz,
                           const mbname_t *mbname, const char *userid);

/* Initialize an XML tree */
xmlNodePtr init_xml_response(const char *resp, int ns,
                             xmlNodePtr req, xmlNsPtr *respNs);

xmlNodePtr xml_add_href(xmlNodePtr parent, xmlNsPtr ns, const char *href);
xmlNodePtr xml_add_error(xmlNodePtr root, struct error_t *err,
                         xmlNsPtr *avail_ns);
xmlNodePtr xml_add_prop(long status, xmlNsPtr davns,
                        struct propstat *propstat,
                        const xmlChar *name, xmlNsPtr ns,
                        xmlChar *content, unsigned precond);
void xml_add_lockdisc(xmlNodePtr node, const char *path, struct dav_data *data);
int ensure_ns(xmlNsPtr *respNs, int ns, xmlNodePtr node,
              const char *url, const char *prefix);

int xml_add_response(struct propfind_ctx *fctx, long code, unsigned precond,
                     const char *desc, const char *location);
int propfind_by_resource(void *rock, void *data);
int propfind_by_collection(const mbentry_t *mbentry, void *rock);
int expand_property(xmlNodePtr inroot, struct propfind_ctx *fctx,
                    struct namespace_t *namespace, const char *href,
                    parse_path_t parse_path, const struct prop_entry *lprops,
                    xmlNodePtr root, int depth);

int preload_proplist(xmlNodePtr proplist, struct propfind_ctx *fctx);
void free_entry_list(struct propfind_entry_list *elist);

/* DAV method processing functions */
int meth_acl(struct transaction_t *txn, void *params);
int meth_copy_move(struct transaction_t *txn, void *params);
int meth_delete(struct transaction_t *txn, void *params);
int meth_get_head(struct transaction_t *txn, void *params);
int meth_lock(struct transaction_t *txn, void *params);
int meth_mkcol(struct transaction_t *txn, void *params);
int meth_propfind(struct transaction_t *txn, void *params);
int meth_proppatch(struct transaction_t *txn, void *params);
int meth_patch(struct transaction_t *txn, void *params);
int meth_post(struct transaction_t *txn, void *params);
int meth_put(struct transaction_t *txn, void *params);
int meth_report(struct transaction_t *txn, void *params);
int meth_unlock(struct transaction_t *txn, void *params);


/* PROPFIND callbacks */

int propfind_getdata(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, struct propstat propstat[],
                     struct mime_type_t *mime_types,
                     struct mime_type_t **out_type,
                     const char *data, unsigned long datalen);
int propfind_fromdb(const xmlChar *name, xmlNsPtr ns,
                    struct propfind_ctx *fctx,
                    xmlNodePtr prop, xmlNodePtr resp,
                    struct propstat propstat[], void *rock);
int propfind_fromhdr(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, xmlNodePtr resp,
                     struct propstat propstat[], void *rock);
int propfind_creationdate(const xmlChar *name, xmlNsPtr ns,
                          struct propfind_ctx *fctx,
                          xmlNodePtr prop, xmlNodePtr resp,
                          struct propstat propstat[], void *rock);
int propfind_collectionname(const xmlChar *name, xmlNsPtr ns,
                            struct propfind_ctx *fctx,
                            xmlNodePtr prop, xmlNodePtr resp,
                            struct propstat propstat[], void *rock);
int propfind_getlength(const xmlChar *name, xmlNsPtr ns,
                       struct propfind_ctx *fctx,
                       xmlNodePtr prop, xmlNodePtr resp,
                       struct propstat propstat[], void *rock);
int propfind_getetag(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, xmlNodePtr resp,
                     struct propstat propstat[], void *rock);
int propfind_getlastmod(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);
int propfind_lockdisc(const xmlChar *name, xmlNsPtr ns,
                      struct propfind_ctx *fctx,
                      xmlNodePtr prop, xmlNodePtr resp,
                      struct propstat propstat[], void *rock);
int propfind_suplock(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, xmlNodePtr resp,
                     struct propstat propstat[], void *rock);

int propfind_reportset(const xmlChar *name, xmlNsPtr ns,
                       struct propfind_ctx *fctx,
                       xmlNodePtr prop, xmlNodePtr resp,
                       struct propstat propstat[], void *rock);

int propfind_methodset(const xmlChar *name, xmlNsPtr ns,
                       struct propfind_ctx *fctx,
                       xmlNodePtr prop, xmlNodePtr,
                       struct propstat propstat[], void *rock);

int propfind_collationset(const xmlChar *name, xmlNsPtr ns,
                          struct propfind_ctx *fctx,
                          xmlNodePtr prop, xmlNodePtr resp,
                          struct propstat propstat[], void *rock);

int propfind_principalurl(const xmlChar *name, xmlNsPtr ns,
                          struct propfind_ctx *fctx,
                          xmlNodePtr prop, xmlNodePtr resp,
                          struct propstat propstat[], void *rock);
int propfind_owner(const xmlChar *name, xmlNsPtr ns,
                   struct propfind_ctx *fctx,
                   xmlNodePtr prop, xmlNodePtr resp,
                   struct propstat propstat[], void *rock);
int propfind_supprivset(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);
int propfind_curprivset(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);
int propfind_acl(const xmlChar *name, xmlNsPtr ns,
                 struct propfind_ctx *fctx,
                 xmlNodePtr prop, xmlNodePtr resp,
                 struct propstat propstat[], void *rock);
int propfind_aclrestrict(const xmlChar *name, xmlNsPtr ns,
                         struct propfind_ctx *fctx,
                         xmlNodePtr prop, xmlNodePtr resp,
                         struct propstat propstat[], void *rock);
int propfind_princolset(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);

int propfind_quota(const xmlChar *name, xmlNsPtr ns,
                   struct propfind_ctx *fctx,
                   xmlNodePtr prop, xmlNodePtr resp,
                   struct propstat propstat[], void *rock);

int propfind_curprin(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, xmlNodePtr resp,
                     struct propstat propstat[], void *rock);

int propfind_serverinfo(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);

int propfind_addmember(const xmlChar *name, xmlNsPtr ns,
                       struct propfind_ctx *fctx,
                       xmlNodePtr prop, xmlNodePtr resp,
                       struct propstat propstat[], void *rock);

int propfind_sync_token(const xmlChar *name, xmlNsPtr ns,
                        struct propfind_ctx *fctx,
                        xmlNodePtr prop, xmlNodePtr resp,
                        struct propstat propstat[], void *rock);

int propfind_bulkrequests(const xmlChar *name, xmlNsPtr ns,
                          struct propfind_ctx *fctx,
                          xmlNodePtr prop, xmlNodePtr resp,
                          struct propstat propstat[], void *rock);

int propfind_calurl(const xmlChar *name, xmlNsPtr ns,
                    struct propfind_ctx *fctx,
                    xmlNodePtr prop, xmlNodePtr resp,
                    struct propstat propstat[], void *rock);
int propfind_caluseraddr(const xmlChar *name, xmlNsPtr ns,
                         struct propfind_ctx *fctx,
                         xmlNodePtr prop, xmlNodePtr resp,
                         struct propstat propstat[], void *rock);
int propfind_caluseremail(const xmlChar *name, xmlNsPtr ns,
                         struct propfind_ctx *fctx,
                         xmlNodePtr prop, xmlNodePtr resp,
                         struct propstat propstat[], void *rock);
int proppatch_caluseraddr(xmlNodePtr prop, unsigned set,
                          struct proppatch_ctx *pctx,
                          struct propstat propstat[], void *rock);
int propfind_calusertype(const xmlChar *name, xmlNsPtr ns,
                         struct propfind_ctx *fctx,
                         xmlNodePtr prop, xmlNodePtr resp,
                         struct propstat propstat[], void *rock);
int propfind_abookhome(const xmlChar *name, xmlNsPtr ns,
                       struct propfind_ctx *fctx,
                       xmlNodePtr prop, xmlNodePtr resp,
                       struct propstat propstat[], void *rock);

int propfind_push_transports(const xmlChar *name, xmlNsPtr ns,
                             struct propfind_ctx *fctx,
                             xmlNodePtr prop, xmlNodePtr resp,
                             struct propstat propstat[], void *rock);
int propfind_pushkey(const xmlChar *name, xmlNsPtr ns,
                     struct propfind_ctx *fctx,
                     xmlNodePtr prop, xmlNodePtr resp,
                     struct propstat propstat[], void *rock);

/* PROPPATCH callbacks */
int proppatch_todb(xmlNodePtr prop, unsigned set, struct proppatch_ctx *pctx,
                   struct propstat propstat[], void *rock);
int proppatch_restype(xmlNodePtr prop, unsigned set, struct proppatch_ctx *pctx,
                      struct propstat propstat[], void *rock);

#endif /* HTTP_DAV_H */