diff options
Diffstat (limited to 'vendor/sabre/dav/bin')
-rwxr-xr-x | vendor/sabre/dav/bin/googlecode_upload.py | 248 | ||||
-rwxr-xr-x | vendor/sabre/dav/bin/migrateto17.php | 284 | ||||
-rwxr-xr-x | vendor/sabre/dav/bin/naturalselection.py | 140 | ||||
-rwxr-xr-x | vendor/sabre/dav/bin/sabredav | 2 | ||||
-rwxr-xr-x | vendor/sabre/dav/bin/sabredav.php | 53 |
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(); |