1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: $responses = array();
13:
14: 15: 16:
17: $sync_level = $xmltree->GetPath('/DAV::sync-collection/DAV::sync-level');
18: if ( empty($sync_level) ) {
19: $sync_level = $request->depth;
20: }
21: else {
22: $sync_level = $sync_level[0]->GetContent();
23: if ( $sync_level == 'infinity' )
24: $sync_level = DEPTH_INFINITY;
25: else
26: $sync_level = 1;
27: }
28:
29: if ( $sync_level == DEPTH_INFINITY ) {
30: $request->PreconditionFailed(403, 'DAV::sync-traversal-supported','This server does not support sync-traversal');
31: }
32:
33: $sync_tokens = $xmltree->GetPath('/DAV::sync-collection/DAV::sync-token');
34: if ( isset($sync_tokens[0]) ) $sync_token = $sync_tokens[0]->GetContent();
35: if ( !isset($sync_token) ) $sync_token = 0;
36: $sync_token = intval(str_replace('data:,', '', strtolower($sync_token) ));
37: dbg_error_log( 'sync', " sync-token: %s", $sync_token );
38:
39: $proplist = array();
40: $props = $xmltree->GetPath('/DAV::sync-collection/DAV::prop/*');
41: if ( !empty($props) ) {
42: foreach( $props AS $k => $v ) {
43: $proplist[] = $v->GetNSTag();
44: }
45: }
46:
47: function display_status( $status_code ) {
48: return sprintf( 'HTTP/1.1 %03d %s', intval($status_code), getStatusMessage($status_code) );
49: }
50:
51: $collection = new DAVResource( $request->path );
52: if ( !$collection->Exists() ) {
53: $request->DoResponse( 404 );
54: }
55: $bound_from = $collection->bound_from();
56: $collection_path = $collection->dav_name();
57: $request_via_binding = ($bound_from != $collection_path);
58:
59: $params = array( ':collection_id' => $collection->GetProperty('collection_id'), ':sync_token' => $sync_token );
60: $sql = "SELECT new_sync_token( :sync_token, :collection_id)";
61: $qry = new AwlQuery($sql, $params);
62: if ( !$qry->Exec("REPORT",__LINE__,__FILE__) || $qry->rows() <= 0 ) {
63: $request->DoResponse( 500, translate("Database error") );
64: }
65: $row = $qry->Fetch();
66:
67: if ( !isset($row->new_sync_token) ) {
68:
69: $sync_token = 0;
70: $params[':sync_token'] = $sync_token;
71: if ( !$qry->QDo($sql, $params) || $qry->rows() <= 0 ) {
72: $request->DoResponse( 500, translate("Database error") );
73: }
74: $row = $qry->Fetch();
75: }
76: $new_token = $row->new_sync_token;
77:
78: if ( $sync_token == $new_token ) {
79:
80: $responses[] = new XMLElement( 'sync-token', 'data:,'.$new_token );
81: }
82: else {
83: $hide_older = '';
84: if ( isset($c->hide_older_than) && intval($c->hide_older_than) > 0 )
85: $hide_older = " AND (CASE WHEN caldav_data.caldav_type<>'VEVENT' OR calendar_item.dtstart IS NULL OR calendar_item.rrule IS NOT NULL THEN true ELSE calendar_item.dtstart > (now() - interval '".intval($c->hide_older_than)." days') END)";
86:
87: $hide_todo = '';
88: if ( isset($c->hide_TODO) && ($c->hide_TODO === true || (is_string($c->hide_TODO) && preg_match($c->hide_TODO, $_SERVER['HTTP_USER_AGENT']))) && ! $collection->HavePrivilegeTo('all') )
89: $hide_todo = " AND (caldav_data.caldav_type NOT IN ('VTODO') OR caldav_data.caldav_type IS NULL) ";
90:
91: if ( $sync_token == 0 ) {
92: $sql = <<<EOSQL
93: SELECT collection.*, calendar_item.*, caldav_data.*, addressbook_resource.*, 201 AS sync_status FROM collection
94: LEFT JOIN caldav_data USING (collection_id)
95: LEFT JOIN calendar_item USING (dav_id)
96: LEFT JOIN addressbook_resource USING (dav_id)
97: WHERE collection.collection_id = :collection_id $hide_older $hide_todo
98: ORDER BY collection.collection_id, caldav_data.dav_id
99: EOSQL;
100: unset($params[':sync_token']);
101: }
102: else {
103: $sql = <<<EOSQL
104: SELECT collection.*, calendar_item.*, caldav_data.*, addressbook_resource.*, sync_changes.*
105: FROM collection LEFT JOIN sync_changes USING(collection_id)
106: LEFT JOIN caldav_data USING (collection_id,dav_id)
107: LEFT JOIN calendar_item USING (collection_id,dav_id)
108: LEFT JOIN addressbook_resource USING (dav_id)
109: WHERE collection.collection_id = :collection_id $hide_older $hide_todo
110: AND sync_time >= (SELECT modification_time FROM sync_tokens WHERE sync_token = :sync_token)
111: EOSQL;
112: if ( isset($c->strict_result_ordering) && $c->strict_result_ordering ) {
113: $sql .= " ORDER BY collection.collection_id, lower(sync_changes.dav_name), sync_changes.sync_time";
114: }
115: else {
116: $sql .= " ORDER BY collection.collection_id, sync_changes.dav_name, sync_changes.sync_time";
117: }
118: }
119: $qry = new AwlQuery($sql, $params );
120:
121: $last_dav_name = '';
122: $first_status = 0;
123:
124: if ( $qry->Exec("REPORT",__LINE__,__FILE__) ) {
125: if ( $qry->rows() > 50 ) {
126:
127: $c->sync_resource_data_ok = false;
128: }
129: while( $object = $qry->Fetch() ) {
130: if ( $request_via_binding )
131: $object->dav_name = str_replace( $bound_from, $collection_path, $object->dav_name);
132:
133: if ( $object->dav_name == $last_dav_name ) {
134:
135: if ( $object->sync_status == 404 ) {
136: array_pop($responses);
137: $resultset = array(
138: new XMLElement( 'href', ConstructURL($object->dav_name) ),
139: new XMLElement( 'status', display_status($object->sync_status) )
140: );
141: $responses[] = new XMLElement( 'response', $resultset );
142: $first_status = 404;
143: }
144: else if ( $object->sync_status == 201 && $first_status == 404 ) {
145:
146: array_pop($responses);
147: $dav_resource = new DAVResource($object);
148: $resultset = $dav_resource->GetPropStat($proplist,$reply);
149: array_unshift($resultset, new XMLElement( 'href', ConstructURL($object->dav_name)));
150: $responses[] = new XMLElement( 'response', $resultset );
151: }
152: 153: 154: 155: 156: 157: 158:
159: }
160: else {
161:
162: if ( $object->sync_status == 404 ) {
163: $resultset = array(
164: new XMLElement( 'href', ConstructURL($object->dav_name) ),
165: new XMLElement( 'status', display_status($object->sync_status) )
166: );
167: $first_status = 404;
168: }
169: else {
170: $dav_resource = new DAVResource($object);
171: $resultset = $dav_resource->GetPropStat($proplist,$reply);
172: array_unshift($resultset, new XMLElement( 'href', ConstructURL($object->dav_name)));
173: $first_status = $object->sync_status;
174: }
175: $responses[] = new XMLElement( 'response', $resultset );
176: $last_dav_name = $object->dav_name;
177: }
178: }
179: $responses[] = new XMLElement( 'sync-token', 'data:,'.$new_token );
180: }
181: else {
182: $request->DoResponse( 500, translate("Database error") );
183: }
184: }
185:
186: $multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() );
187:
188: $request->XMLResponse( 207, $multistatus );
189: