aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/dav/bin
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/dav/bin')
-rwxr-xr-xvendor/sabre/dav/bin/googlecode_upload.py248
-rwxr-xr-xvendor/sabre/dav/bin/migrateto17.php284
-rwxr-xr-xvendor/sabre/dav/bin/naturalselection.py140
-rwxr-xr-xvendor/sabre/dav/bin/sabredav2
-rwxr-xr-xvendor/sabre/dav/bin/sabredav.php53
5 files changed, 727 insertions, 0 deletions
diff --git a/vendor/sabre/dav/bin/googlecode_upload.py b/vendor/sabre/dav/bin/googlecode_upload.py
new file mode 100755
index 000000000..caafd5ded
--- /dev/null
+++ b/vendor/sabre/dav/bin/googlecode_upload.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, 2007 Google Inc. All Rights Reserved.
+# Author: danderson@google.com (David Anderson)
+#
+# Script for uploading files to a Google Code project.
+#
+# This is intended to be both a useful script for people who want to
+# streamline project uploads and a reference implementation for
+# uploading files to Google Code projects.
+#
+# To upload a file to Google Code, you need to provide a path to the
+# file on your local machine, a small summary of what the file is, a
+# project name, and a valid account that is a member or owner of that
+# project. You can optionally provide a list of labels that apply to
+# the file. The file will be uploaded under the same name that it has
+# in your local filesystem (that is, the "basename" or last path
+# component). Run the script with '--help' to get the exact syntax
+# and available options.
+#
+# Note that the upload script requests that you enter your
+# googlecode.com password. This is NOT your Gmail account password!
+# This is the password you use on googlecode.com for committing to
+# Subversion and uploading files. You can find your password by going
+# to http://code.google.com/hosting/settings when logged in with your
+# Gmail account. If you have already committed to your project's
+# Subversion repository, the script will automatically retrieve your
+# credentials from there (unless disabled, see the output of '--help'
+# for details).
+#
+# If you are looking at this script as a reference for implementing
+# your own Google Code file uploader, then you should take a look at
+# the upload() function, which is the meat of the uploader. You
+# basically need to build a multipart/form-data POST request with the
+# right fields and send it to https://PROJECT.googlecode.com/files .
+# Authenticate the request using HTTP Basic authentication, as is
+# shown below.
+#
+# Licensed under the terms of the Apache Software License 2.0:
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Questions, comments, feature requests and patches are most welcome.
+# Please direct all of these to the Google Code users group:
+# http://groups.google.com/group/google-code-hosting
+
+"""Google Code file uploader script.
+"""
+
+__author__ = 'danderson@google.com (David Anderson)'
+
+import httplib
+import os.path
+import optparse
+import getpass
+import base64
+import sys
+
+
+def upload(file, project_name, user_name, password, summary, labels=None):
+ """Upload a file to a Google Code project's file server.
+
+ Args:
+ file: The local path to the file.
+ project_name: The name of your project on Google Code.
+ user_name: Your Google account name.
+ password: The googlecode.com password for your account.
+ Note that this is NOT your global Google Account password!
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+
+ Returns: a tuple:
+ http_status: 201 if the upload succeeded, something else if an
+ error occurred.
+ http_reason: The human-readable string associated with http_status
+ file_url: If the upload succeeded, the URL of the file on Google
+ Code, None otherwise.
+ """
+ # The login is the user part of user@gmail.com. If the login provided
+ # is in the full user@domain form, strip it down.
+ if user_name.endswith('@gmail.com'):
+ user_name = user_name[:user_name.index('@gmail.com')]
+
+ form_fields = [('summary', summary)]
+ if labels is not None:
+ form_fields.extend([('label', l.strip()) for l in labels])
+
+ content_type, body = encode_upload_request(form_fields, file)
+
+ upload_host = '%s.googlecode.com' % project_name
+ upload_uri = '/files'
+ auth_token = base64.b64encode('%s:%s'% (user_name, password))
+ headers = {
+ 'Authorization': 'Basic %s' % auth_token,
+ 'User-Agent': 'Googlecode.com uploader v0.9.4',
+ 'Content-Type': content_type,
+ }
+
+ server = httplib.HTTPSConnection(upload_host)
+ server.request('POST', upload_uri, body, headers)
+ resp = server.getresponse()
+ server.close()
+
+ if resp.status == 201:
+ location = resp.getheader('Location', None)
+ else:
+ location = None
+ return resp.status, resp.reason, location
+
+
+def encode_upload_request(fields, file_path):
+ """Encode the given fields and file into a multipart form body.
+
+ fields is a sequence of (name, value) pairs. file is the path of
+ the file to upload. The file will be uploaded to Google Code with
+ the same file name.
+
+ Returns: (content_type, body) ready for httplib.HTTP instance
+ """
+ BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla'
+ CRLF = '\r\n'
+
+ body = []
+
+ # Add the metadata about the upload first
+ for key, value in fields:
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="%s"' % key,
+ '',
+ value,
+ ])
+
+ # Now add the file itself
+ file_name = os.path.basename(file_path)
+ f = open(file_path, 'rb')
+ file_content = f.read()
+ f.close()
+
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="filename"; filename="%s"'
+ % file_name,
+ # The upload server determines the mime-type, no need to set it.
+ 'Content-Type: application/octet-stream',
+ '',
+ file_content,
+ ])
+
+ # Finalize the form body
+ body.extend(['--' + BOUNDARY + '--', ''])
+
+ return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body)
+
+
+def upload_find_auth(file_path, project_name, summary, labels=None,
+ user_name=None, password=None, tries=3):
+ """Find credentials and upload a file to a Google Code project's file server.
+
+ file_path, project_name, summary, and labels are passed as-is to upload.
+
+ Args:
+ file_path: The local path to the file.
+ project_name: The name of your project on Google Code.
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+ config_dir: Path to Subversion configuration directory, 'none', or None.
+ user_name: Your Google account name.
+ tries: How many attempts to make.
+ """
+
+ while tries > 0:
+ if user_name is None:
+ # Read username if not specified or loaded from svn config, or on
+ # subsequent tries.
+ sys.stdout.write('Please enter your googlecode.com username: ')
+ sys.stdout.flush()
+ user_name = sys.stdin.readline().rstrip()
+ if password is None:
+ # Read password if not loaded from svn config, or on subsequent tries.
+ print 'Please enter your googlecode.com password.'
+ print '** Note that this is NOT your Gmail account password! **'
+ print 'It is the password you use to access Subversion repositories,'
+ print 'and can be found here: http://code.google.com/hosting/settings'
+ password = getpass.getpass()
+
+ status, reason, url = upload(file_path, project_name, user_name, password,
+ summary, labels)
+ # Returns 403 Forbidden instead of 401 Unauthorized for bad
+ # credentials as of 2007-07-17.
+ if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]:
+ # Rest for another try.
+ user_name = password = None
+ tries = tries - 1
+ else:
+ # We're done.
+ break
+
+ return status, reason, url
+
+
+def main():
+ parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY '
+ '-p PROJECT [options] FILE')
+ parser.add_option('-s', '--summary', dest='summary',
+ help='Short description of the file')
+ parser.add_option('-p', '--project', dest='project',
+ help='Google Code project name')
+ parser.add_option('-u', '--user', dest='user',
+ help='Your Google Code username')
+ parser.add_option('-w', '--password', dest='password',
+ help='Your Google Code password')
+ parser.add_option('-l', '--labels', dest='labels',
+ help='An optional list of comma-separated labels to attach '
+ 'to the file')
+
+ options, args = parser.parse_args()
+
+ if not options.summary:
+ parser.error('File summary is missing.')
+ elif not options.project:
+ parser.error('Project name is missing.')
+ elif len(args) < 1:
+ parser.error('File to upload not provided.')
+ elif len(args) > 1:
+ parser.error('Only one file may be specified.')
+
+ file_path = args[0]
+
+ if options.labels:
+ labels = options.labels.split(',')
+ else:
+ labels = None
+
+ status, reason, url = upload_find_auth(file_path, options.project,
+ options.summary, labels,
+ options.user, options.password)
+ if url:
+ print 'The file was uploaded successfully.'
+ print 'URL: %s' % url
+ return 0
+ else:
+ print 'An error occurred. Your file was not uploaded.'
+ print 'Google Code upload server said: %s (%s)' % (reason, status)
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/vendor/sabre/dav/bin/migrateto17.php b/vendor/sabre/dav/bin/migrateto17.php
new file mode 100755
index 000000000..66a9ee564
--- /dev/null
+++ b/vendor/sabre/dav/bin/migrateto17.php
@@ -0,0 +1,284 @@
+#!/usr/bin/env php
+<?php
+
+echo "SabreDAV migrate script for version 1.7\n";
+
+if ($argc<2) {
+
+ echo <<<HELLO
+
+This script help you migrate from a pre-1.7 database to 1.7 and later\n
+Both the 'calendarobjects' and 'calendars' tables will be upgraded.
+
+If you do not have this table, or don't use the default PDO CalDAV backend
+it's pointless to run this script.
+
+Keep in mind that some processing will be done on every single record of this
+table and in addition, ALTER TABLE commands will be executed.
+If you have a large calendarobjects table, this may mean that this process
+takes a while.
+
+Usage:
+
+php {$argv[0]} [pdo-dsn] [username] [password]
+
+For example:
+
+php {$argv[0]} "mysql:host=localhost;dbname=sabredav" root password
+php {$argv[0]} sqlite:data/sabredav.db
+
+HELLO;
+
+ exit();
+
+}
+
+// There's a bunch of places where the autoloader could be, so we'll try all of
+// them.
+$paths = array(
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/../../../autoload.php',
+);
+
+foreach($paths as $path) {
+ if (file_exists($path)) {
+ include $path;
+ break;
+ }
+}
+
+$dsn = $argv[1];
+$user = isset($argv[2])?$argv[2]:null;
+$pass = isset($argv[3])?$argv[3]:null;
+
+echo "Connecting to database: " . $dsn . "\n";
+
+$pdo = new PDO($dsn, $user, $pass);
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+
+echo "Validating existing table layout\n";
+
+// The only cross-db way to do this, is to just fetch a single record.
+$row = $pdo->query("SELECT * FROM calendarobjects LIMIT 1")->fetch();
+
+if (!$row) {
+ echo "Error: This database did not have any records in the calendarobjects table, you should just recreate the table.\n";
+ exit(-1);
+}
+
+$requiredFields = array(
+ 'id',
+ 'calendardata',
+ 'uri',
+ 'calendarid',
+ 'lastmodified',
+);
+
+foreach($requiredFields as $requiredField) {
+ if (!array_key_exists($requiredField,$row)) {
+ echo "Error: The current 'calendarobjects' table was missing a field we expected to exist.\n";
+ echo "For safety reasons, this process is stopped.\n";
+ exit(-1);
+ }
+}
+
+$fields17 = array(
+ 'etag',
+ 'size',
+ 'componenttype',
+ 'firstoccurence',
+ 'lastoccurence',
+);
+
+$found = 0;
+foreach($fields17 as $field) {
+ if (array_key_exists($field, $row)) {
+ $found++;
+ }
+}
+
+if ($found === 0) {
+ echo "The database had the 1.6 schema. Table will now be altered.\n";
+ echo "This may take some time for large tables\n";
+
+ switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
+
+ case 'mysql' :
+
+ $pdo->exec(<<<SQL
+ALTER TABLE calendarobjects
+ADD etag VARCHAR(32),
+ADD size INT(11) UNSIGNED,
+ADD componenttype VARCHAR(8),
+ADD firstoccurence INT(11) UNSIGNED,
+ADD lastoccurence INT(11) UNSIGNED
+SQL
+ );
+ break;
+ case 'sqlite' :
+ $pdo->exec('ALTER TABLE calendarobjects ADD etag text');
+ $pdo->exec('ALTER TABLE calendarobjects ADD size integer');
+ $pdo->exec('ALTER TABLE calendarobjects ADD componenttype TEXT');
+ $pdo->exec('ALTER TABLE calendarobjects ADD firstoccurence integer');
+ $pdo->exec('ALTER TABLE calendarobjects ADD lastoccurence integer');
+ break;
+
+ default :
+ die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n");
+
+ }
+ echo "Database schema upgraded.\n";
+
+} elseif ($found === 5) {
+
+ echo "Database already had the 1.7 schema\n";
+
+} else {
+
+ echo "The database had $found out of 5 from the changes for 1.7. This is scary and unusual, so we have to abort.\n";
+ echo "You can manually try to upgrade the schema, and then run this script again.\n";
+ exit(-1);
+
+}
+
+echo "Now, we need to parse every record and pull out some information.\n";
+
+$result = $pdo->query('SELECT id, calendardata FROM calendarobjects');
+$stmt = $pdo->prepare('UPDATE calendarobjects SET etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ? WHERE id = ?');
+
+echo "Total records found: " . $result->rowCount() . "\n";
+$done = 0;
+$total = $result->rowCount();
+while($row = $result->fetch()) {
+
+ try {
+ $newData = getDenormalizedData($row['calendardata']);
+ } catch (Exception $e) {
+ echo "===\nException caught will trying to parser calendarobject.\n";
+ echo "Error message: " . $e->getMessage() . "\n";
+ echo "Record id: " . $row['id'] . "\n";
+ echo "This record is ignored, you should inspect it to see if there's anything wrong.\n===\n";
+ continue;
+ }
+ $stmt->execute(array(
+ $newData['etag'],
+ $newData['size'],
+ $newData['componentType'],
+ $newData['firstOccurence'],
+ $newData['lastOccurence'],
+ $row['id'],
+ ));
+ $done++;
+
+ if ($done % 500 === 0) {
+ echo "Completed: $done / $total\n";
+ }
+}
+echo "Completed: $done / $total\n";
+
+echo "Checking the calendars table needs changes.\n";
+$row = $pdo->query("SELECT * FROM calendars LIMIT 1")->fetch();
+
+if (array_key_exists('transparent', $row)) {
+
+ echo "The calendars table is already up to date\n";
+
+} else {
+
+ echo "Adding the 'transparent' field to the calendars table\n";
+
+ switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
+
+ case 'mysql' :
+ $pdo->exec("ALTER TABLE calendars ADD transparent TINYINT(1) NOT NULL DEFAULT '0'");
+ break;
+ case 'sqlite' :
+ $pdo->exec("ALTER TABLE calendars ADD transparent bool");
+ break;
+
+ default :
+ die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n");
+
+ }
+
+}
+
+echo "Process completed!\n";
+
+/**
+ * Parses some information from calendar objects, used for optimized
+ * calendar-queries.
+ *
+ * Blantently copied from Sabre\CalDAV\Backend\PDO
+ *
+ * Returns an array with the following keys:
+ * * etag
+ * * size
+ * * componentType
+ * * firstOccurence
+ * * lastOccurence
+ *
+ * @param string $calendarData
+ * @return array
+ */
+function getDenormalizedData($calendarData) {
+
+ $vObject = \Sabre\VObject\Reader::read($calendarData);
+ $componentType = null;
+ $component = null;
+ $firstOccurence = null;
+ $lastOccurence = null;
+ foreach($vObject->getComponents() as $component) {
+ if ($component->name!=='VTIMEZONE') {
+ $componentType = $component->name;
+ break;
+ }
+ }
+ if (!$componentType) {
+ throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
+ }
+ if ($componentType === 'VEVENT') {
+ $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
+ // Finding the last occurence is a bit harder
+ if (!isset($component->RRULE)) {
+ if (isset($component->DTEND)) {
+ $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
+ } elseif (isset($component->DURATION)) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->add(\Sabre\VObject\DateTimeParser::parse($component->DURATION->value));
+ $lastOccurence = $endDate->getTimeStamp();
+ } elseif (!$component->DTSTART->hasTime()) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->modify('+1 day');
+ $lastOccurence = $endDate->getTimeStamp();
+ } else {
+ $lastOccurence = $firstOccurence;
+ }
+ } else {
+ $it = new \Sabre\VObject\RecurrenceIterator($vObject, (string)$component->UID);
+ $maxDate = new DateTime(\Sabre\CalDAV\Backend\PDO::MAX_DATE);
+ if ($it->isInfinite()) {
+ $lastOccurence = $maxDate->getTimeStamp();
+ } else {
+ $end = $it->getDtEnd();
+ while($it->valid() && $end < $maxDate) {
+ $end = $it->getDtEnd();
+ $it->next();
+
+ }
+ $lastOccurence = $end->getTimeStamp();
+ }
+
+ }
+ }
+
+ return array(
+ 'etag' => md5($calendarData),
+ 'size' => strlen($calendarData),
+ 'componentType' => $componentType,
+ 'firstOccurence' => $firstOccurence,
+ 'lastOccurence' => $lastOccurence,
+ );
+
+}
diff --git a/vendor/sabre/dav/bin/naturalselection.py b/vendor/sabre/dav/bin/naturalselection.py
new file mode 100755
index 000000000..aa5554dd0
--- /dev/null
+++ b/vendor/sabre/dav/bin/naturalselection.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2009-2010 Evert Pot
+# All rights reserved.
+# http://www.rooftopsolutions.nl/
+#
+# This utility is distributed along with SabreDAV
+# license: http://code.google.com/p/sabredav/wiki/License Modified BSD License
+
+import os
+from optparse import OptionParser
+import time
+
+def getfreespace(path):
+ stat = os.statvfs(path)
+ return stat.f_frsize * stat.f_bavail
+
+def getbytesleft(path,treshold):
+ return getfreespace(path)-treshold
+
+def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0):
+
+ bytes = getbytesleft(cacheDir,treshold)
+ if (bytes>0):
+ print "Bytes to go before we hit treshhold:", bytes
+ else:
+ print "Treshold exceeded with:", -bytes, "bytes"
+ dir = os.listdir(cacheDir)
+ dir2 = []
+ for file in dir:
+ path = cacheDir + '/' + file
+ dir2.append({
+ "path" : path,
+ "atime": os.stat(path).st_atime,
+ "size" : os.stat(path).st_size
+ })
+
+ dir2.sort(lambda x,y: int(x["atime"]-y["atime"]))
+
+ filesunlinked = 0
+ gainedspace = 0
+
+ # Left is the amount of bytes that need to be freed up
+ # The default is the 'min_erase setting'
+ left = min_erase
+
+ # If the min_erase setting is lower than the amount of bytes over
+ # the treshold, we use that number instead.
+ if left < -bytes :
+ left = -bytes
+
+ print "Need to delete at least:", left;
+
+ for file in dir2:
+
+ # Only deleting files if we're not simulating
+ if not simulate: os.unlink(file["path"])
+ left = int(left - file["size"])
+ gainedspace = gainedspace + file["size"]
+ filesunlinked = filesunlinked + 1
+
+ if(left<0):
+ break
+
+ print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace)
+
+
+ time.sleep(sleep)
+
+
+
+def main():
+ parser = OptionParser(
+ version="naturalselecton v0.3",
+ description="Cache directory manager. Deletes cache entries based on accesstime and free space tresholds.\n" +
+ "This utility is distributed alongside SabreDAV.",
+ usage="usage: %prog [options] cacheDirectory",
+ )
+ parser.add_option(
+ '-s',
+ dest="simulate",
+ action="store_true",
+ help="Don't actually make changes, but just simulate the behaviour",
+ )
+ parser.add_option(
+ '-r','--runs',
+ help="How many times to check before exiting. -1 is infinite, which is the default",
+ type="int",
+ dest="runs",
+ default=-1
+ )
+ parser.add_option(
+ '-n','--interval',
+ help="Sleep time in seconds (default = 5)",
+ type="int",
+ dest="sleep",
+ default=5
+ )
+ parser.add_option(
+ '-l','--treshold',
+ help="Treshhold in bytes (default = 10737418240, which is 10GB)",
+ type="int",
+ dest="treshold",
+ default=10737418240
+ )
+ parser.add_option(
+ '-m', '--min-erase',
+ help="Minimum number of bytes to erase when the treshold is reached. " +
+ "Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
+ "(the default is 1073741824, which is 1GB.)",
+ type="int",
+ dest="min_erase",
+ default=1073741824
+ )
+
+ options,args = parser.parse_args()
+ if len(args)<1:
+ parser.error("This utility requires at least 1 argument")
+ cacheDir = args[0]
+
+ print "Natural Selection"
+ print "Cache directory:", cacheDir
+ free = getfreespace(cacheDir);
+ print "Current free disk space:", free
+
+ runs = options.runs;
+ while runs!=0 :
+ run(
+ cacheDir,
+ sleep=options.sleep,
+ simulate=options.simulate,
+ treshold=options.treshold,
+ min_erase=options.min_erase
+ )
+ if runs>0:
+ runs = runs - 1
+
+if __name__ == '__main__' :
+ main()
diff --git a/vendor/sabre/dav/bin/sabredav b/vendor/sabre/dav/bin/sabredav
new file mode 100755
index 000000000..032371ba8
--- /dev/null
+++ b/vendor/sabre/dav/bin/sabredav
@@ -0,0 +1,2 @@
+#!/bin/sh
+php -S 0.0.0.0:8080 `dirname $0`/sabredav.php
diff --git a/vendor/sabre/dav/bin/sabredav.php b/vendor/sabre/dav/bin/sabredav.php
new file mode 100755
index 000000000..34a674fd5
--- /dev/null
+++ b/vendor/sabre/dav/bin/sabredav.php
@@ -0,0 +1,53 @@
+<?php
+
+// SabreDAV test server.
+
+class CliLog {
+
+ protected $stream;
+
+ function __construct() {
+
+ $this->stream = fopen('php://stdout','w');
+
+ }
+
+ function log($msg) {
+ fwrite($this->stream, $msg . "\n");
+ }
+
+}
+
+$log = new CliLog();
+
+if (php_sapi_name()!=='cli-server') {
+ die("This script is intended to run on the built-in php webserver");
+}
+
+// Finding composer
+
+
+$paths = array(
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/../../../autoload.php',
+);
+
+foreach($paths as $path) {
+ if (file_exists($path)) {
+ include $path;
+ break;
+ }
+}
+
+use Sabre\DAV;
+
+// Root
+$root = new DAV\FS\Directory(getcwd());
+
+// Setting up server.
+$server = new DAV\Server($root);
+
+// Browser plugin
+$server->addPlugin(new DAV\Browser\Plugin());
+
+$server->exec();