[3733] | 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 ); |
---|