DAViCal
caldav-BIND.php
1 <?php
11 dbg_error_log('BIND', 'method handler');
12 require_once('AwlQuery.php');
13 
14 $request->NeedPrivilege('DAV::bind');
15 
16 if ( ! $request->IsCollection() ) {
17  $request->PreconditionFailed(403,'DAV::bind-into-collection',translate('The BIND Request-URI MUST identify a collection.'));
18 }
19 $parent_container = $request->path;
20 if ( preg_match( '{[^/]$}', $parent_container ) ) $parent_container .= '/';
21 
22 require_once('DAVResource.php');
23 $parent = new DAVResource( $parent_container );
24 if ( ! $parent->Exists() || $parent->IsSchedulingCollection() ) {
25  $request->PreconditionFailed(403, 'DAV::method-not-allowed',translate('The BIND method is not allowed at that location.') );
26 }
27 
28 require_once('XMLDocument.php');
29 $reply = new XMLDocument(array( 'DAV:' => '' ));
30 
31 $position = 0;
32 $xmltree = BuildXMLTree( $request->xml_tags, $position);
33 
34 $segment = $xmltree->GetElements('DAV::segment');
35 $segment = $segment[0]->GetContent();
36 
37 if ( preg_match( '{[/\\\\]}', $segment ) ) {
38  $request->PreconditionFailed(403, 'DAV::name-allowed',translate('That destination name contains invalid characters.') );
39 }
40 
41 $href = $xmltree->GetElements('DAV::href');
42 $href = $href[0]->GetContent();
43 
44 $destination_path = $parent_container . $segment .'/';
45 $destination = new DAVResource( $destination_path );
46 if ( $destination->Exists() ) {
47  $request->PreconditionFailed(403,'DAV::can-overwrite',translate('A resource already exists at the destination.'));
48 }
49 
50 // external binds shouldn't ever point back to ourselves but they should be a valid http[s] url
51 if ( preg_match ( '{^(?:https?://|file:///)([^/]+)(:[0-9]\+)?/.+$}', $href, $matches )
52  && strcasecmp( $matches[0], 'localhost' ) !== 0 && strcasecmp( $matches[0], '127.0.0.1' ) !== 0
53  && strcasecmp( $matches[0], $_SERVER['SERVER_NAME'] ) !== 0 && strcasecmp( $matches[0], $_SERVER['SERVER_ADDR'] ) !== 0 ) {
54  require_once('external-fetch.php');
55  $qry = new AwlQuery( );
56  $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array( ':dav_name' => '/.external/'. md5($href) ));
57  if ( $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
58  $dav_id = $row->collection_id;
59  }
60  else {
61  create_external ( '/.external/'. md5($href) ,true,false );
62  $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array( ':dav_name' => '/.external/'. md5($href) ));
63  if ( $qry->rows() != 1 || !($row = $qry->Fetch()) )
64  $request->DoResponse(500,translate('Database Error'));
65  $dav_id = $row->collection_id;
66  }
67 
68  $sql = 'INSERT INTO dav_binding ( bound_source_id, access_ticket_id, dav_owner_id, parent_container, dav_name, dav_displayname, external_url, type )
69  VALUES( :target_id, :ticket_id, :session_principal, :parent_container, :dav_name, :displayname, :external_url, :external_type )';
70  $params = array(
71  ':target_id' => $dav_id,
72  ':ticket_id' => null,
73  ':parent_container' => $parent->dav_name(),
74  ':session_principal' => $session->principal_id,
75  ':dav_name' => $destination_path,
76  ':displayname' => $segment,
77  ':external_url' => $href,
78  ':external_type' => 'calendar'
79  );
80  $qry = new AwlQuery( $sql, $params );
81  if ( $qry->Exec('BIND',__LINE__,__FILE__) ) {
82  $qry = new AwlQuery( 'SELECT bind_id from dav_binding where dav_name = :dav_name', array( ':dav_name' => $destination_path ) );
83  if ( ! $qry->Exec('BIND',__LINE__,__FILE__) || $qry->rows() != 1 || !($row = $qry->Fetch()) )
84  $request->DoResponse(500,translate('Database Error'));
85  fetch_external ( $row->bind_id, '', $c->external_ua_string );
86  $request->DoResponse(201);
87  }
88  else {
89  $request->DoResponse(500,translate('Database Error'));
90  }
91 }
92 else {
93  $source = new DAVResource( $href );
94  if ( !$source->Exists() ) {
95  $request->PreconditionFailed(403,'DAV::bind-source-exists',translate('The BIND Request MUST identify an existing resource.'));
96  }
97 
98  if ( $source->IsPrincipal() || !$source->IsCollection() ) {
99  $request->PreconditionFailed(403,'DAV::binding-allowed',translate('DAViCal only allows BIND requests for collections at present.'));
100  }
101 
102  if ( $source->IsBinding() )
103  $source = new DAVResource( $source->bound_from() );
104 
105 
106  /*
107  bind_id INT8 DEFAULT nextval('dav_id_seq') PRIMARY KEY,
108  bound_source_id INT8 REFERENCES collection(collection_id) ON UPDATE CASCADE ON DELETE CASCADE,
109  access_ticket_id TEXT REFERENCES access_ticket(ticket_id) ON UPDATE CASCADE ON DELETE SET NULL,
110  parent_container TEXT NOT NULL,
111  dav_name TEXT UNIQUE NOT NULL,
112  dav_displayname TEXT,
113  external_url TEXT,
114  type TEXT
115  */
116 
117  $sql = 'INSERT INTO dav_binding ( bound_source_id, access_ticket_id, dav_owner_id, parent_container, dav_name, dav_displayname )
118  VALUES( :target_id, :ticket_id, :session_principal, :parent_container, :dav_name, :displayname )';
119  $params = array(
120  ':target_id' => $source->GetProperty('collection_id'),
121  ':ticket_id' => (isset($request->ticket) ? $request->ticket->id() : null),
122  ':parent_container' => $parent->dav_name(),
123  ':session_principal' => $session->principal_id,
124  ':dav_name' => $destination_path,
125  ':displayname' => $source->GetProperty('displayname')
126  );
127  $qry = new AwlQuery( $sql, $params );
128  if ( $qry->Exec('BIND',__LINE__,__FILE__) ) {
129  header('Location: '. ConstructURL($destination_path) );
130 
131  // Uncache anything to do with the target
132  $cache = getCacheInstance();
133  $cache_ns = 'collection-'.$destination_path;
134  $cache->delete( $cache_ns, null );
135 
136  $request->DoResponse(201);
137  }
138  else {
139  $request->DoResponse(500,translate('Database Error'));
140  }
141 }
DAVResource
Definition: DAVResource.php:24