1 | <?php |
---|
2 | /** |
---|
3 | * CalDAV Server - handle sync-collection report (draft-daboo-webdav-sync-01) |
---|
4 | * |
---|
5 | * @package davical |
---|
6 | * @subpackage caldav |
---|
7 | * @author Andrew McMillan <andrew@mcmillan.net.nz> |
---|
8 | * @copyright Morphoss Ltd - http://www.morphoss.com/ |
---|
9 | * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later |
---|
10 | */ |
---|
11 | |
---|
12 | $responses = array(); |
---|
13 | |
---|
14 | /** |
---|
15 | * Build the array of properties to include in the report output |
---|
16 | */ |
---|
17 | $sync_tokens = $xmltree->GetPath('/DAV::sync-collection/DAV::sync-token'); |
---|
18 | $sync_token = $sync_tokens[0]->GetContent(); |
---|
19 | if ( !isset($sync_token) ) $sync_token = 0; |
---|
20 | $sync_token = intval($sync_token); |
---|
21 | dbg_error_log( 'sync', " sync-token: %s", $sync_token ); |
---|
22 | |
---|
23 | |
---|
24 | $props = $xmltree->GetElements('DAV::prop'); |
---|
25 | $v = $props[0]; |
---|
26 | $props = $v->GetContent(); |
---|
27 | $proplist = array(); |
---|
28 | foreach( $props AS $k => $v ) { |
---|
29 | $proplist[] = $v->GetTag(); |
---|
30 | } |
---|
31 | |
---|
32 | function display_status( $status_code ) { |
---|
33 | return sprintf( 'HTTP/1.1 %03d %s', intval($status_code), getStatusMessage($status_code) ); |
---|
34 | } |
---|
35 | |
---|
36 | $collection = new DAVResource( $request->path ); |
---|
37 | |
---|
38 | $params = array( ':collection_id' => $collection->GetProperty('collection_id'), ':sync_token' => $sync_token ); |
---|
39 | $sql = "SELECT new_sync_token( :sync_token, :collection_id)"; |
---|
40 | $qry = new AwlQuery($sql, $params); |
---|
41 | if ( !$qry->Exec("REPORT",__LINE__,__FILE__) || $qry->rows() <= 0 ) { |
---|
42 | $request->DoResponse( 500, translate("Database error") ); |
---|
43 | } |
---|
44 | $row = $qry->Fetch(); |
---|
45 | |
---|
46 | if ( !isset($row->new_sync_token) ) { |
---|
47 | /** If we got a null back then they gave us a sync token we know not of, so provide a full sync */ |
---|
48 | $sync_token =0; |
---|
49 | $params[':sync_token'] = $sync_token; |
---|
50 | if ( !$qry->QDo($sql, $params) || $qry->rows() <= 0 ) { |
---|
51 | $request->DoResponse( 500, translate("Database error") ); |
---|
52 | } |
---|
53 | $row = $qry->Fetch(); |
---|
54 | } |
---|
55 | $new_token = $row->new_sync_token; |
---|
56 | |
---|
57 | if ( $sync_token == 0 ) { |
---|
58 | $sql = <<<EOSQL |
---|
59 | SELECT collection.*, calendar_item.*, caldav_data.*, addressbook_resource.*, 201 AS sync_status FROM collection |
---|
60 | LEFT JOIN caldav_data USING (collection_id) |
---|
61 | LEFT JOIN calendar_item USING (dav_id) |
---|
62 | LEFT JOIN addressbook_resource USING (dav_id) |
---|
63 | WHERE collection.collection_id = :collection_id |
---|
64 | ORDER BY collection.collection_id, caldav_data.dav_id |
---|
65 | EOSQL; |
---|
66 | unset($params[':sync_token']); |
---|
67 | } |
---|
68 | else { |
---|
69 | $sql = <<<EOSQL |
---|
70 | SELECT collection.*, calendar_item.*, caldav_data.*, addressbook_resource.*, sync_changes.* |
---|
71 | FROM collection LEFT JOIN sync_changes USING(collection_id) |
---|
72 | LEFT JOIN caldav_data USING (collection_id,dav_id) |
---|
73 | LEFT JOIN calendar_item USING (collection_id,dav_id) |
---|
74 | LEFT JOIN addressbook_resource USING (dav_id) |
---|
75 | WHERE collection.collection_id = :collection_id |
---|
76 | AND sync_time > (SELECT modification_time FROM sync_tokens WHERE sync_token = :sync_token) |
---|
77 | ORDER BY collection.collection_id, sync_changes.dav_name, sync_changes.sync_time |
---|
78 | EOSQL; |
---|
79 | } |
---|
80 | $qry = new AwlQuery($sql, $params ); |
---|
81 | |
---|
82 | $last_dav_name = ''; |
---|
83 | $first_status = 0; |
---|
84 | |
---|
85 | if ( $qry->Exec("REPORT",__LINE__,__FILE__) ) { |
---|
86 | while( $object = $qry->Fetch() ) { |
---|
87 | if ( $object->dav_name == $last_dav_name ) { |
---|
88 | /** The complex case: this is the second or subsequent for this dav_id */ |
---|
89 | if ( $object->sync_status == 404 ) { |
---|
90 | array_pop($responses); |
---|
91 | $resultset = array( |
---|
92 | new XMLElement( 'href', ConstructURL($object->dav_name) ), |
---|
93 | new XMLElement( 'status', display_status($object->sync_status) ) |
---|
94 | ); |
---|
95 | $responses[] = new XMLElement( 'sync-response', $resultset ); |
---|
96 | $first_status = 404; |
---|
97 | } |
---|
98 | else if ( $object->sync_status == 201 && $first_status == 404 ) { |
---|
99 | // ... Delete ... Create ... is indicated as a create, but don't forget we started with a delete |
---|
100 | array_pop($responses); |
---|
101 | $resultset = array( |
---|
102 | new XMLElement( 'href', ConstructURL($object->dav_name) ), |
---|
103 | new XMLElement( 'status', display_status($object->sync_status) ) |
---|
104 | ); |
---|
105 | $responses[] = new XMLElement( 'sync-response', $resultset ); |
---|
106 | } |
---|
107 | /** Else: |
---|
108 | * the object existed at start and we have multiple modifications, |
---|
109 | * or, |
---|
110 | * the object didn't exist at start and we have subsequent modifications, |
---|
111 | * but: |
---|
112 | * in either case we simply stick with our first report. |
---|
113 | */ |
---|
114 | } |
---|
115 | else { |
---|
116 | /** The simple case: this is the first one for this dav_id */ |
---|
117 | $resultset = array( |
---|
118 | new XMLElement( 'href', ConstructURL($object->dav_name) ), |
---|
119 | new XMLElement( 'status', display_status($object->sync_status) ) |
---|
120 | ); |
---|
121 | if ( $object->sync_status != 404 ) { |
---|
122 | $dav_resource = new DAVResource($object); |
---|
123 | $resultset = array_merge( $resultset, $dav_resource->GetPropStat($proplist,$reply) ); |
---|
124 | } |
---|
125 | $response_tag = 'response'; |
---|
126 | if ( isset($c->use_old_sync_response_tag) && $c->use_old_sync_response_tag ) $response_tag = 'sync-response'; |
---|
127 | $responses[] = new XMLElement( $response_tag, $resultset ); |
---|
128 | $first_status = $object->sync_status; |
---|
129 | $last_dav_name = $object->dav_name; |
---|
130 | } |
---|
131 | } |
---|
132 | $responses[] = new XMLElement( 'sync-token', $new_token ); |
---|
133 | } |
---|
134 | else { |
---|
135 | $request->DoResponse( 500, translate("Database error") ); |
---|
136 | } |
---|
137 | |
---|
138 | $multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() ); |
---|
139 | |
---|
140 | $request->XMLResponse( 207, $multistatus ); |
---|