summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/calendar/ajax/import/calendarcheck.php18
-rw-r--r--apps/calendar/ajax/import/dialog.php2
-rw-r--r--apps/calendar/ajax/import/dropimport.php89
-rw-r--r--apps/calendar/ajax/import/import.php76
-rw-r--r--apps/calendar/appinfo/app.php3
-rw-r--r--apps/calendar/css/import.css14
-rw-r--r--apps/calendar/js/calendar.js19
-rw-r--r--apps/calendar/js/loader.js214
-rw-r--r--apps/calendar/js/settings.js4
-rw-r--r--apps/calendar/l10n/de.php41
-rw-r--r--apps/calendar/l10n/it.php50
-rw-r--r--apps/calendar/l10n/vi.php135
-rw-r--r--apps/calendar/lib/calendar.php36
-rw-r--r--apps/calendar/lib/connector_sabre.php8
-rw-r--r--apps/calendar/lib/import.php334
-rw-r--r--apps/calendar/templates/part.import.php74
-rw-r--r--apps/contacts/ajax/loadphoto.php46
-rw-r--r--apps/contacts/css/contacts.css9
-rw-r--r--apps/contacts/js/contacts.js433
-rw-r--r--apps/contacts/js/loader.js4
-rw-r--r--apps/contacts/l10n/it.php103
-rw-r--r--apps/contacts/l10n/vi.php48
-rw-r--r--apps/contacts/templates/index.php32
-rw-r--r--apps/files/ajax/newfile.php58
-rw-r--r--apps/files/ajax/scan.php5
-rw-r--r--apps/files/appinfo/update.php11
-rw-r--r--apps/files/appinfo/version2
-rw-r--r--apps/files/js/files.js36
-rw-r--r--apps/files/l10n/es.php14
-rw-r--r--apps/files/l10n/it.php14
-rw-r--r--apps/files/l10n/vi.php31
-rw-r--r--apps/files_imageviewer/js/jquery.fancybox-1.3.4.js4
-rw-r--r--apps/files_imageviewer/js/jquery.fancybox-1.3.4.pack.js2
-rw-r--r--apps/files_sharing/sharedstorage.php2
-rw-r--r--apps/gallery/l10n/de.php8
-rw-r--r--apps/gallery/l10n/es.php8
-rw-r--r--apps/gallery/l10n/it.php8
-rw-r--r--apps/gallery/l10n/vi.php11
-rw-r--r--apps/media/l10n/vi.php14
-rw-r--r--apps/user_ldap/appinfo/app.php14
-rw-r--r--apps/user_ldap/group_ldap.php94
-rw-r--r--apps/user_ldap/lib/access.php597
-rw-r--r--apps/user_ldap/lib/connection.php255
-rw-r--r--apps/user_ldap/lib_ldap.php721
-rw-r--r--apps/user_ldap/tests/group_ldap.php4
-rw-r--r--apps/user_ldap/user_ldap.php72
-rw-r--r--apps/user_migrate/templates/settings.php2
-rw-r--r--apps/user_openid/class.openid.v3.php326
-rw-r--r--apps/user_openid/phpmyid.php1707
-rw-r--r--apps/user_openid/user.php2
-rw-r--r--apps/user_openid/user_openid.php2
51 files changed, 2480 insertions, 3336 deletions
diff --git a/apps/calendar/ajax/import/calendarcheck.php b/apps/calendar/ajax/import/calendarcheck.php
new file mode 100644
index 00000000000..a91bab70573
--- /dev/null
+++ b/apps/calendar/ajax/import/calendarcheck.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+OCP\JSON::checkLoggedIn();
+OCP\App::checkAppEnabled('calendar');
+$calname = strip_tags($_POST['calname']);
+$calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser());
+foreach($calendars as $calendar){
+ if($calendar['displayname'] == $calname){
+ OCP\JSON::success(array('message'=>'exists'));
+ exit;
+ }
+}
+OCP\JSON::error(); \ No newline at end of file
diff --git a/apps/calendar/ajax/import/dialog.php b/apps/calendar/ajax/import/dialog.php
index b99c32278c4..18fe226172c 100644
--- a/apps/calendar/ajax/import/dialog.php
+++ b/apps/calendar/ajax/import/dialog.php
@@ -5,8 +5,6 @@
* later.
* See the COPYING-README file.
*/
-
-
OCP\JSON::checkLoggedIn();
OCP\App::checkAppEnabled('calendar');
$tmpl = new OCP\Template('calendar', 'part.import');
diff --git a/apps/calendar/ajax/import/dropimport.php b/apps/calendar/ajax/import/dropimport.php
index 87667d4de68..f46e7314098 100644
--- a/apps/calendar/ajax/import/dropimport.php
+++ b/apps/calendar/ajax/import/dropimport.php
@@ -1,73 +1,32 @@
<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev@georgswebsite.de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
$data = $_POST['data'];
$data = explode(',', $data);
$data = end($data);
$data = base64_decode($data);
OCP\JSON::checkLoggedIn();
OCP\App::checkAppEnabled('calendar');
-$nl="\r\n";
-$comps = array('VEVENT'=>true, 'VTODO'=>true, 'VJOURNAL'=>true);
-$data = str_replace(array("\r","\n\n"), array("\n","\n"), $data);
-$lines = explode("\n", $data);
-unset($data);
-$comp=$uid=$cal=false;
-$cals=$uids=array();
-$i = 0;
-foreach($lines as $line) {
- if(strpos($line, ':')!==false) {
- list($attr, $val) = explode(':', strtoupper($line));
- if ($attr == 'BEGIN' && $val == 'VCALENDAR') {
- $cal = $i;
- $cals[$cal] = array('first'=>$i,'last'=>$i,'end'=>$i);
- } elseif ($attr =='BEGIN' && $cal!==false && isset($comps[$val])) {
- $comp = $val;
- $beginNo = $i;
- } elseif ($attr == 'END' && $cal!==false && $val == 'VCALENDAR') {
- if($comp!==false) {
- unset($cals[$cal]); // corrupt calendar, unset it
- } else {
- $cals[$cal]['end'] = $i;
- }
- $comp=$uid=$cal=false; // reset calendar
- } elseif ($attr == 'END' && $comp!==false && $val == $comp) {
- if(! $uid) {
- $uid = OC_Calendar_Object::createUID();
- }
- $uids[$uid][$beginNo] = array('end'=>$i, 'cal'=>$cal);
- if ($cals[$cal]['first'] == $cal) {
- $cals[$cal]['first'] = $beginNo;
- }
- $cals[$cal]['last'] = $i;
- $comp=$uid=false; // reset component
- } elseif ($attr =="UID" && $comp!==false) {
- list($attr, $uid) = explode(':', $line);
- }
- }
- $i++;
+$import = new OC_Calendar_Import($data);
+$import->setUserID(OCP\User::getUser());
+$import->setTimeZone(OC_Calendar_App::$tz);
+$import->disableProgressCache();
+if(!$import->isValid()){
+ OCP\JSON::error();
+ exit;
}
-$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true);
-$id = $calendars[0]['id'];
-foreach($uids as $uid) {
- $prefix=$suffix=$content=array();
- foreach($uid as $begin=>$details) {
- $cal = $details['cal'];
- if(!isset($cals[$cal])) {
- continue; // from corrupt/incomplete calendar
- }
- $cdata = $cals[$cal];
- // if we have multiple components from different calendar objects,
- // we should really merge their elements (enhancement?) -- 1st one wins for now.
- if(! count($prefix)) {
- $prefix = array_slice($lines, $cal, $cdata['first'] - $cal);
- }
- if(! count($suffix)) {
- $suffix = array_slice($lines, $cdata['last']+1, $cdata['end'] - $cdata['last']);
- }
- $content = array_merge($content, array_slice($lines, $begin, $details['end'] - $begin + 1));
- }
- if(count($content)) {
- $import = join($nl, array_merge($prefix, $content, $suffix)) . $nl;
- OC_Calendar_Object::add($id, $import);
- }
-}
-OCP\JSON::success(); \ No newline at end of file
+$newcalendarname = strip_tags($import->createCalendarName());
+$newid = OC_Calendar_Calendar::addCalendar(OCP\User::getUser(),$newcalendarname,'VEVENT,VTODO,VJOURNAL',null,0,$import->createCalendarColor());
+$import->setCalendarID($newid);
+$import->import();
+$count = $import->getCount();
+if($count == 0){
+ OC_Calendar_Calendar::deleteCalendar($newid);
+ OCP\JSON::error(array('message'=>OC_Calendar_App::$l10n->t('The file contained either no events or all events are already saved in your calendar.')));
+}else{
+ OCP\JSON::success(array('message'=>$count . ' ' . OC_Calendar_App::$l10n->t('events has been saved in the new calendar') . ' ' . $newcalendarname, 'eventSource'=>OC_Calendar_Calendar::getEventSourceInfo(OC_Calendar_Calendar::find($newid))));
+} \ No newline at end of file
diff --git a/apps/calendar/ajax/import/import.php b/apps/calendar/ajax/import/import.php
index 38008af4a9d..b1dfc464d00 100644
--- a/apps/calendar/ajax/import/import.php
+++ b/apps/calendar/ajax/import/import.php
@@ -5,42 +5,71 @@
* later.
* See the COPYING-README file.
*/
-//check for calendar rights or create new one
-ob_start();
-
OCP\JSON::checkLoggedIn();
OCP\App::checkAppEnabled('calendar');
OCP\JSON::callCheck();
session_write_close();
-
-$nl="\r\n";
-$comps = array('VEVENT'=>true, 'VTODO'=>true, 'VJOURNAL'=>true);
-
-global $progresskey;
-$progresskey = 'calendar.import-' . $_POST['progresskey'];
-
-if (isset($_POST['progress']) && $_POST['progress']) {
- echo OC_Cache::get($progresskey);
- die;
+if (isset($_POST['progresskey']) && isset($_POST['getprogress'])) {
+ echo OCP\JSON::success(array('percent'=>OC_Cache::get($_POST['progresskey'])));
+ exit;
}
-
-function writeProgress($pct) {
- global $progresskey;
- OC_Cache::set($progresskey, $pct, 300);
-}
-writeProgress('10');
$file = OC_Filesystem::file_get_contents($_POST['path'] . '/' . $_POST['file']);
+if(!$file){
+ OCP\JSON::error(array('error'=>'404'));
+}
+$import = new OC_Calendar_Import($file);
+$import->setUserID(OCP\User::getUser());
+$import->setTimeZone(OC_Calendar_App::$tz);
+$import->enableProgressCache();
+$import->setProgresskey($_POST['progresskey']);
+if(!$import->isValid()){
+ OCP\JSON::error(array('error'=>'notvalid'));
+ exit;
+}
+$newcal = false;
if($_POST['method'] == 'new'){
- $id = OC_Calendar_Calendar::addCalendar(OCP\USER::getUser(), $_POST['calname']);
- OC_Calendar_Calendar::setCalendarActive($id, 1);
+ $calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser());
+ foreach($calendars as $calendar){
+ if($calendar['displayname'] == $_POST['calname']){
+ $id = $calendar['id'];
+ $newcal = false;
+ break;
+ }
+ $newcal = true;
+ }
+ if($newcal){
+ $id = OC_Calendar_Calendar::addCalendar(OCP\USER::getUser(), strip_tags($_POST['calname']),'VEVENT,VTODO,VJOURNAL',null,0,strip_tags($_POST['calcolor']));
+ OC_Calendar_Calendar::setCalendarActive($id, 1);
+ }
}else{
$calendar = OC_Calendar_App::getCalendar($_POST['id']);
if($calendar['userid'] != OCP\USER::getUser()){
- OCP\JSON::error();
+ OCP\JSON::error(array('error'=>'missingcalendarrights'));
exit();
}
$id = $_POST['id'];
}
+$import->setCalendarID($id);
+try{
+ $import->import();
+}catch (Exception $e) {
+ OCP\JSON::error(array('message'=>OC_Calendar_App::$l10n->t('Import failed'), 'debug'=>$e->getMessage()));
+ //write some log
+}
+$count = $import->getCount();
+if($count == 0){
+ if($newcal){
+ OC_Calendar_Calendar::deleteCalendar($id);
+ }
+ OCP\JSON::error(array('message'=>OC_Calendar_App::$l10n->t('The file contained either no events or all events are already saved in your calendar.')));
+}else{
+ if($newcal){
+ OCP\JSON::success(array('message'=>$count . ' ' . OC_Calendar_App::$l10n->t('events has been saved in the new calendar') . ' ' . strip_tags($_POST['calname'])));
+ }else{
+ OCP\JSON::success(array('message'=>$count . ' ' . OC_Calendar_App::$l10n->t('events has been saved in your calendar')));
+ }
+}
+/* //////////////////////////// Attention: following code is quite painfull !!! ///////////////////////
writeProgress('20');
// normalize the newlines
$file = str_replace(array("\r","\n\n"), array("\n","\n"), $file);
@@ -92,7 +121,6 @@ foreach($lines as $line) {
// import the calendar
writeProgress('60');
foreach($uids as $uid) {
-
$prefix=$suffix=$content=array();
foreach($uid as $begin=>$details) {
@@ -120,4 +148,4 @@ foreach($uids as $uid) {
writeProgress('100');
sleep(3);
OC_Cache::remove($progresskey);
-OCP\JSON::success(); \ No newline at end of file
+OCP\JSON::success();*/
diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php
index c8fccc326c3..4fdba291262 100644
--- a/apps/calendar/appinfo/app.php
+++ b/apps/calendar/appinfo/app.php
@@ -9,6 +9,7 @@ OC::$CLASSPATH['OC_Calendar_Repeat'] = 'apps/calendar/lib/repeat.php';
OC::$CLASSPATH['OC_Calendar_Share'] = 'apps/calendar/lib/share.php';
OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php';
OC::$CLASSPATH['OC_Calendar_Export'] = 'apps/calendar/lib/export.php';
+OC::$CLASSPATH['OC_Calendar_Import'] = 'apps/calendar/lib/import.php';
//General Hooks
OCP\Util::connectHook('OC_User', 'post_createUser', 'OC_Calendar_Hooks', 'createUser');
OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser');
@@ -24,6 +25,8 @@ OCP\Util::connectHook('OC_Calendar', 'deleteCalendar', 'OC_Calendar_Share', 'pos
OCP\Util::addscript('calendar','loader');
OCP\Util::addscript("3rdparty", "chosen/chosen.jquery.min");
OCP\Util::addStyle("3rdparty", "chosen/chosen");
+OCP\Util::addStyle('3rdparty/miniColors', 'jquery.miniColors');
+OCP\Util::addscript('3rdparty/miniColors', 'jquery.miniColors.min');
OCP\App::addNavigationEntry( array(
'id' => 'calendar_index',
'order' => 10,
diff --git a/apps/calendar/css/import.css b/apps/calendar/css/import.css
new file mode 100644
index 00000000000..8abdc3aecd1
--- /dev/null
+++ b/apps/calendar/css/import.css
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+#calendar_import_newcalform, #calendar_import_mergewarning, #calendar_import_process, #calendar_import_done{display:none;}
+#calendar_import_process_message, #calendar_import_status, #calendar_import_form_message, #calendar_import_mergewarning{text-align:center;}
+#calendar_import_form_message{font-weight: bold;}
+#calendar_import_newcalendar{width:415px;float:right;}
+#calendar_import_mergewarning{clear: both;}
+#calendar_import_defaultcolors{clear:both;margin: 0 auto;text-align: center;}
+.calendar_import_warning{border-color: #fc3333;}
+.calendar-colorpicker-color{display:inline-block;width:20px;height:5px;margin: 0 auto;cursor:pointer;border:2px solid transparent;} \ No newline at end of file
diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js
index 004b2386fb1..25311fa0df4 100644
--- a/apps/calendar/js/calendar.js
+++ b/apps/calendar/js/calendar.js
@@ -622,18 +622,11 @@ Calendar={
drop:function(e){
var files = e.dataTransfer.files;
for(var i = 0;i < files.length;i++){
- var file = files[i]
+ var file = files[i];
reader = new FileReader();
reader.onload = function(event){
- if(file.type != 'text/calendar'){
- $('#notification').html('At least one file don\'t seems to be a calendar file. File skipped.');
- $('#notification').slideDown();
- window.setTimeout(function(){$('#notification').slideUp();}, 5000);
- return false;
- }else{
- Calendar.UI.Drop.import(event.target.result);
- $('#calendar_holder').fullCalendar('refetchEvents');
- }
+ Calendar.UI.Drop.import(event.target.result);
+ $('#calendar_holder').fullCalendar('refetchEvents');
}
reader.readAsDataURL(file);
}
@@ -641,9 +634,13 @@ Calendar={
import:function(data){
$.post(OC.filePath('calendar', 'ajax/import', 'dropimport.php'), {'data':data},function(result) {
if(result.status == 'success'){
+ $('#calendar_holder').fullCalendar('addEventSource', result.eventSource);
+ $('#notification').html(result.message);
+ $('#notification').slideDown();
+ window.setTimeout(function(){$('#notification').slideUp();}, 5000);
return true;
}else{
- $('#notification').html('ownCloud wasn\'t able to import at least one file. File skipped.');
+ $('#notification').html(result.message);
$('#notification').slideDown();
window.setTimeout(function(){$('#notification').slideUp();}, 5000);
}
diff --git a/apps/calendar/js/loader.js b/apps/calendar/js/loader.js
index cef95afc3aa..b28d19ab00e 100644
--- a/apps/calendar/js/loader.js
+++ b/apps/calendar/js/loader.js
@@ -5,77 +5,175 @@
* See the COPYING-README file.
*/
Calendar_Import={
- importdialog: function(filename){
- var path = $('#dir').val();
- $('body').append('<div id="calendar_import"></div>');
- $('#calendar_import').load(OC.filePath('calendar', 'ajax/import', 'dialog.php'), {filename:filename, path:path}, function(){Calendar_Import.initdialog(filename);});
+ Store:{
+ file: '',
+ path: '',
+ id: 0,
+ method: '',
+ calname: '',
+ calcolor: '',
+ progresskey: '',
+ percentage: 0
},
- initdialog: function(filename){
- $('#calendar_import_dialog').dialog({
- width : 500,
- close : function() {
- $(this).dialog('destroy').remove();
- $('#calendar_import').remove();
+ Dialog:{
+ open: function(filename){
+ OC.addStyle('calendar', 'import');
+ Calendar_Import.Store.file = filename;
+ Calendar_Import.Store.path = $('#dir').val();
+ $('body').append('<div id="calendar_import"></div>');
+ $('#calendar_import').load(OC.filePath('calendar', 'ajax/import', 'dialog.php'), {filename:Calendar_Import.Store.file, path:Calendar_Import.Store.path},function(){
+ Calendar_Import.Dialog.init();
+ });
+ },
+ close: function(){
+ Calendar_Import.reset();
+ $(this).dialog('destroy').remove();
+ $('#calendar_import_dialog').remove();
+ },
+ init: function(){
+ //init dialog
+ $('#calendar_import_dialog').dialog({
+ width : 500,
+ resizable: false,
+ close : function() {
+ Calendar_Import.Dialog.close();
+ }
+ });
+ //init buttons
+ $('#calendar_import_done').click(function(){
+ Calendar_Import.Dialog.close();
+ });
+ $('#calendar_import_submit').click(function(){
+ Calendar_Import.Core.process();
+ });
+ $('#calendar_import_mergewarning').click(function(){
+ $('#calendar_import_newcalendar').attr('value', $('#calendar_import_availablename').val());
+ Calendar_Import.Dialog.mergewarning($('#calendar_import_newcalendar').val());
+ });
+ $('#calendar_import_calendar').change(function(){
+ if($('#calendar_import_calendar option:selected').val() == 'newcal'){
+ $('#calendar_import_newcalform').slideDown('slow');
+ Calendar_Import.Dialog.mergewarning($('#calendar_import_newcalendar').val());
+ }else{
+ $('#calendar_import_newcalform').slideUp('slow');
+ $('#calendar_import_mergewarning').slideUp('slow');
+ }
+ });
+ $('#calendar_import_newcalendar').keyup(function(){
+ Calendar_Import.Dialog.mergewarning($.trim($('#calendar_import_newcalendar').val()));
+ });
+ $('#calendar_import_newcalendar_color').miniColors({
+ letterCase: 'uppercase'
+ });
+ $('.calendar-colorpicker-color').click(function(){
+ var str = $(this).attr('rel');
+ str = str.substr(1);
+ $('#calendar_import_newcalendar_color').attr('value', str);
+ $(".color-picker").miniColors('value', '#' + str);
+ });
+ //init progressbar
+ $('#calendar_import_progressbar').progressbar({value: Calendar_Import.Store.percentage});
+ Calendar_Import.Store.progresskey = $('#calendar_import_progresskey').val();
+ },
+ mergewarning: function(newcalname){
+ $.post(OC.filePath('calendar', 'ajax/import', 'calendarcheck.php'), {calname: newcalname}, function(data){
+ if(data.message == 'exists'){
+ $('#calendar_import_mergewarning').slideDown('slow');
+ }else{
+ $('#calendar_import_mergewarning').slideUp('slow');
+ }
+ });
+ },
+ update: function(){
+ if(Calendar_Import.Store.percentage == 100){
+ return false;
}
- });
- $('#import_done_button').click(function(){
- $('#calendar_import_dialog').dialog('destroy').remove();
- $('#calendar_import').remove();
- });
- $('#progressbar').progressbar({value: 0});
- $('#startimport').click(function(){
- var filename = $('#filename').val();
- var path = $('#path').val();
- var calid = $('#calendar option:selected').val();
- if($('#calendar option:selected').val() == 'newcal'){
- var method = 'new';
- var calname = $('#newcalendar').val();
- var calname = $.trim(calname);
- if(calname == ''){
- $('#newcalendar').css('background-color', '#FF2626');
- $('#newcalendar').focus(function(){
- $('#newcalendar').css('background-color', '#F8F8F8');
- });
- return false;
+ $.post(OC.filePath('calendar', 'ajax/import', 'import.php'), {progresskey: Calendar_Import.Store.progresskey, getprogress: true}, function(data){
+ if(data.status == 'success'){
+ if(data.percent == null){
+ return false;
+ }
+ Calendar_Import.Store.percentage = parseInt(data.percent);
+ $('#calendar_import_progressbar').progressbar('option', 'value', parseInt(data.percent));
+ if(data.percent < 100 ){
+ window.setTimeout('Calendar_Import.Dialog.update()', 250);
+ }else{
+ $('#calendar_import_done').css('display', 'block');
+ }
+ }else{
+ $('#calendar_import_progressbar').progressbar('option', 'value', 100);
+ $('#calendar_import_progressbar > div').css('background-color', '#FF2626');
+ $('#calendar_import_status').html(data.message);
}
- }else{
- var method = 'old';
+ });
+ return 0;
+ },
+ warning: function(selector){
+ $(selector).addClass('calendar_import_warning');
+ $(selector).focus(function(){
+ $(selector).removeClass('calendar_import_warning');
+ });
+ }
+ },
+ Core:{
+ process: function(){
+ var validation = Calendar_Import.Core.prepare();
+ if(validation){
+ $('#calendar_import_form').css('display', 'none');
+ $('#calendar_import_process').css('display', 'block');
+ $('#calendar_import_newcalendar').attr('readonly', 'readonly');
+ $('#calendar_import_calendar').attr('disabled', 'disabled');
+ Calendar_Import.Core.send();
+ window.setTimeout('Calendar_Import.Dialog.update()', 250);
}
- $('#newcalendar').attr('readonly', 'readonly');
- $('#calendar').attr('disabled', 'disabled');
- var progresskey = $('#progresskey').val();
- $.post(OC.filePath('calendar', 'ajax/import', 'import.php'), {progresskey: progresskey, method: String (method), calname: String (calname), path: String (path), file: String (filename), id: String (calid)}, function(data){
+ },
+ send: function(){
+ $.post(OC.filePath('calendar', 'ajax/import', 'import.php'),
+ {progresskey: Calendar_Import.Store.progresskey, method: String (Calendar_Import.Store.method), calname: String (Calendar_Import.Store.calname), path: String (Calendar_Import.Store.path), file: String (Calendar_Import.Store.file), id: String (Calendar_Import.Store.id), calcolor: String (Calendar_Import.Store.calcolor)}, function(data){
if(data.status == 'success'){
- $('#progressbar').progressbar('option', 'value', 100);
- $('#import_done').css('display', 'block');
+ $('#calendar_import_progressbar').progressbar('option', 'value', 100);
+ Calendar_Import.Store.percentage = 100;
+ $('#calendar_import_done').css('display', 'block');
+ $('#calendar_import_status').html(data.message);
+ }else{
+ $('#calendar_import_progressbar').progressbar('option', 'value', 100);
+ $('#calendar_import_progressbar > div').css('background-color', '#FF2626');
+ $('#calendar_import_status').html(data.message);
}
});
- $('#form_container').css('display', 'none');
- $('#progressbar_container').css('display', 'block');
- window.setTimeout('Calendar_Import.getimportstatus(\'' + progresskey + '\')', 500);
- });
- $('#calendar').change(function(){
- if($('#calendar option:selected').val() == 'newcal'){
- $('#newcalform').slideDown('slow');
+ },
+ prepare: function(){
+ Calendar_Import.Store.id = $('#calendar_import_calendar option:selected').val();
+ if($('#calendar_import_calendar option:selected').val() == 'newcal'){
+ Calendar_Import.Store.method = 'new';
+ Calendar_Import.Store.calname = $.trim($('#calendar_import_newcalendar').val());
+ if(Calendar_Import.Store.calname == ''){
+ Calendar_Import.Dialog.warning('#calendar_import_newcalendar');
+ return false;
+ }
+ Calendar_Import.Store.calcolor = $.trim($('#calendar_import_newcalendar_color').val());
+ if(Calendar_Import.Store.calcolor == ''){
+ Calendar_Import.Store.calcolor = $('.calendar-colorpicker-color:first').attr('rel');
+ }
}else{
- $('#newcalform').slideUp('slow');
+ Calendar_Import.Store.method = 'old';
}
- });
+ return true;
+ }
},
- getimportstatus: function(progresskey){
- $.post(OC.filePath('calendar', 'ajax/import', 'import.php'), {progress:1,progresskey: progresskey}, function(percent){
- $('#progressbar').progressbar('option', 'value', parseInt(percent));
- if(percent < 100){
- window.setTimeout('Calendar_Import.getimportstatus(\'' + progresskey + '\')', 500);
- }else{
- $('#import_done').css('display', 'block');
- }
- });
+ reset: function(){
+ Calendar_Import.Store.file = '';
+ Calendar_Import.Store.path = '';
+ Calendar_Import.Store.id = 0;
+ Calendar_Import.Store.method = '';
+ Calendar_Import.Store.calname = '';
+ Calendar_Import.Store.progresskey = '';
+ Calendar_Import.Store.percentage = 0;
}
}
$(document).ready(function(){
if(typeof FileActions !== 'undefined'){
- FileActions.register('text/calendar','importcal', '', Calendar_Import.importdialog);
- FileActions.setDefault('text/calendar','importcal');
+ FileActions.register('text/calendar','importCalendar', '', Calendar_Import.Dialog.open);
+ FileActions.setDefault('text/calendar','importCalendar');
};
});
diff --git a/apps/calendar/js/settings.js b/apps/calendar/js/settings.js
index 03e4217573d..60741f2b6fc 100644
--- a/apps/calendar/js/settings.js
+++ b/apps/calendar/js/settings.js
@@ -34,6 +34,7 @@ $(document).ready(function(){
$.getJSON(OC.filePath('calendar', 'ajax/settings', 'timeformat.php'), function(jsondata, status) {
$('#' + jsondata.timeformat).attr('selected',true);
$('#timeformat').chosen();
+ $('#timeformat_chzn').css('width', '100px');
});
$.getJSON(OC.filePath('calendar', 'ajax/settings', 'gettimezonedetection.php'), function(jsondata, status){
if(jsondata.detection == 'true'){
@@ -43,6 +44,7 @@ $(document).ready(function(){
$.getJSON(OC.filePath('calendar', 'ajax/settings', 'getfirstday.php'), function(jsondata, status) {
$('#' + jsondata.firstday).attr('selected',true);
$('#firstday').chosen();
+ $('#firstday_chzn').css('width', '100px');
});
$('#cleancalendarcache').click(function(){
$.getJSON(OC.filePath('calendar', 'ajax/cache', 'rescan.php'), function(){
@@ -55,7 +57,7 @@ function calendarcachecheck(){
$.getJSON(OC.filePath('calendar', 'ajax/cache', 'status.php'), function(jsondata, status) {
$('#cleancalendarcache').attr('title', jsondata.l10n.text);
if(jsondata.status == 'success'){
- $('#cleancalendarcache').css('background', '#90EE90');
+ $('#cleancalendarcache').css('background', '#F8F8F8');
$('#cleancalendarcache').css('color', '#333');
$('#cleancalendarcache').css('text-shadow', '#fff 0 1px 0');
}else{
diff --git a/apps/calendar/l10n/de.php b/apps/calendar/l10n/de.php
index f12a18baad0..33c924ac2c3 100644
--- a/apps/calendar/l10n/de.php
+++ b/apps/calendar/l10n/de.php
@@ -2,11 +2,17 @@
"No calendars found." => "Keine Kalender gefunden",
"No events found." => "Keine Termine gefunden",
"Wrong calendar" => "Falscher Kalender",
+"Import failed" => "Import fehlgeschlagen",
"New Timezone:" => "Neue Zeitzone:",
"Timezone changed" => "Zeitzone geändert",
"Invalid request" => "Fehlerhafte Anfrage",
"Calendar" => "Kalender",
-"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}" => "ddd d MMMM[ yyyy]{ -[ddd d] MMMM yyyy}",
+"ddd" => "ddd",
+"ddd M/d" => "ddd d.M",
+"dddd M/d" => "dddd d.M",
+"MMMM yyyy" => "MMMM yyyy",
+"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}" => "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
+"dddd, MMM d, yyyy" => "dddd, d. MMM yyyy",
"Birthday" => "Geburtstag",
"Business" => "Geschäftlich",
"Call" => "Anruf",
@@ -22,7 +28,9 @@
"Projects" => "Projekte",
"Questions" => "Fragen",
"Work" => "Arbeit",
+"by" => "von",
"unnamed" => "unbenannt",
+"New Calendar" => "Neuer Kalender",
"Does not repeat" => "einmalig",
"Daily" => "täglich",
"Weekly" => "wöchentlich",
@@ -67,8 +75,26 @@
"by day and month" => "nach Tag und Monat",
"Date" => "Datum",
"Cal." => "Kal.",
+"Sun." => "So",
+"Mon." => "Mo",
+"Tue." => "Di",
+"Wed." => "Mi",
+"Thu." => "Do",
+"Fri." => "Fr",
+"Sat." => "Sa",
+"Jan." => "Jan.",
+"Feb." => "Feb.",
+"Mar." => "Mär.",
+"Apr." => "Apr.",
+"May." => "Mai",
+"Jun." => "Jun.",
+"Jul." => "Jul.",
+"Aug." => "Aug.",
+"Sep." => "Sep.",
+"Oct." => "Okt.",
+"Nov." => "Nov.",
+"Dec." => "Dez.",
"All day" => "Ganztags",
-"New Calendar" => "Neuer Kalender",
"Missing fields" => "fehlende Felder",
"Title" => "Titel",
"From Date" => "Startdatum",
@@ -132,18 +158,14 @@
"Interval" => "Intervall",
"End" => "Ende",
"occurrences" => "Termine",
-"Import a calendar file" => "Kalenderdatei Importieren",
-"Please choose the calendar" => "Bitte wählen Sie den Kalender.",
"create a new calendar" => "Neuen Kalender anlegen",
+"Import a calendar file" => "Kalenderdatei Importieren",
"Name of new calendar" => "Kalendername",
"Import" => "Importieren",
-"Importing calendar" => "Kalender wird importiert.",
-"Calendar imported successfully" => "Kalender erfolgreich importiert",
"Close Dialog" => "Dialog schließen",
"Create a new event" => "Neues Ereignis",
"View an event" => "Termin öffnen",
"No categories selected" => "Keine Kategorie ausgewählt",
-"Select category" => "Kategorie auswählen",
"of" => "von",
"at" => "um",
"Timezone" => "Zeitzone",
@@ -152,9 +174,8 @@
"24h" => "24h",
"12h" => "12h",
"First day of the week" => "erster Wochentag",
-"Calendar CalDAV syncing address:" => "Kalender CalDAV Synchronisationsadresse:",
-"Users" => "Nutzer",
-"select users" => "Nutzer auswählen",
+"Users" => "Benutzer",
+"select users" => "Benutzer auswählen",
"Editable" => "editierbar",
"Groups" => "Gruppen",
"select groups" => "Gruppen auswählen",
diff --git a/apps/calendar/l10n/it.php b/apps/calendar/l10n/it.php
index cdb2d99c82e..b91e8b0df0b 100644
--- a/apps/calendar/l10n/it.php
+++ b/apps/calendar/l10n/it.php
@@ -1,12 +1,23 @@
<?php $TRANSLATIONS = array(
+"Not all calendars are completely cached" => "Non tutti i calendari sono mantenuti completamente in cache",
+"Everything seems to be completely cached" => "Tutto sembra essere mantenuto completamente in cache",
"No calendars found." => "Nessun calendario trovato.",
"No events found." => "Nessun evento trovato.",
"Wrong calendar" => "Calendario sbagliato",
+"The file contained either no events or all events are already saved in your calendar." => "Il file non conteneva alcun evento o tutti gli eventi erano già salvati nel tuo calendario.",
+"events has been saved in the new calendar" => "gli eventi sono stati salvati nel nuovo calendario",
+"Import failed" => "Importazione non riuscita",
+"events has been saved in your calendar" => "gli eventi sono stati salvati nel tuo calendario",
"New Timezone:" => "Nuovo fuso orario:",
"Timezone changed" => "Fuso orario cambiato",
"Invalid request" => "Richiesta non valida",
"Calendar" => "Calendario",
+"ddd" => "ggg",
+"ddd M/d" => "ggg M/g",
+"dddd M/d" => "gggg M/g",
+"MMMM yyyy" => "MMMM aaaa",
"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}" => "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
+"dddd, MMM d, yyyy" => "gggg, MMM g, aaaa",
"Birthday" => "Compleanno",
"Business" => "Azienda",
"Call" => "Chiama",
@@ -22,7 +33,9 @@
"Projects" => "Progetti",
"Questions" => "Domande",
"Work" => "Lavoro",
+"by" => "da",
"unnamed" => "senza nome",
+"New Calendar" => "Nuovo calendario",
"Does not repeat" => "Non ripetere",
"Daily" => "Giornaliero",
"Weekly" => "Settimanale",
@@ -67,8 +80,26 @@
"by day and month" => "per giorno e mese",
"Date" => "Data",
"Cal." => "Cal.",
+"Sun." => "Dom.",
+"Mon." => "Lun.",
+"Tue." => "Mar.",
+"Wed." => "Mer.",
+"Thu." => "Gio.",
+"Fri." => "Ven.",
+"Sat." => "Sab.",
+"Jan." => "Gen.",
+"Feb." => "Feb.",
+"Mar." => "Mar.",
+"Apr." => "Apr.",
+"May." => "Mag.",
+"Jun." => "Giu.",
+"Jul." => "Lug.",
+"Aug." => "Ago.",
+"Sep." => "Set.",
+"Oct." => "Ott.",
+"Nov." => "Nov.",
+"Dec." => "Dic.",
"All day" => "Tutti il giorno",
-"New Calendar" => "Nuovo calendario",
"Missing fields" => "Campi mancanti",
"Title" => "Titolo",
"From Date" => "Dal giorno",
@@ -132,18 +163,17 @@
"Interval" => "Intervallo",
"End" => "Fine",
"occurrences" => "occorrenze",
-"Import a calendar file" => "Importa un file di calendario",
-"Please choose the calendar" => "Scegli il calendario",
"create a new calendar" => "Crea un nuovo calendario",
+"Import a calendar file" => "Importa un file di calendario",
+"Please choose a calendar" => "Scegli un calendario",
"Name of new calendar" => "Nome del nuovo calendario",
+"Take an available name!" => "Usa un nome disponibile!",
+"A Calendar with this name already exists. If you continue anyhow, these calendars will be merged." => "Un calendario con questo nome esiste già. Se continui, i due calendari saranno uniti.",
"Import" => "Importa",
-"Importing calendar" => "Importazione del calendario in corso",
-"Calendar imported successfully" => "Calendario importato correttamente",
"Close Dialog" => "Chiudi la finestra di dialogo",
"Create a new event" => "Crea un nuovo evento",
"View an event" => "Visualizza un evento",
"No categories selected" => "Nessuna categoria selezionata",
-"Select category" => "Seleziona una categoria",
"of" => "di",
"at" => "alle",
"Timezone" => "Fuso orario",
@@ -152,7 +182,13 @@
"24h" => "24h",
"12h" => "12h",
"First day of the week" => "Primo giorno della settimana",
-"Calendar CalDAV syncing address:" => "Indirizzo sincronizzazione calendario CalDAV:",
+"Cache" => "Cache",
+"Clear cache for repeating events" => "Cancella gli eventi che si ripetono dalla cache",
+"Calendar CalDAV syncing addresses" => "Indirizzi di sincronizzazione calendari CalDAV",
+"more info" => "ulteriori informazioni",
+"Primary address (Kontact et al)" => "Indirizzo principale (Kontact e altri)",
+"iOS/OS X" => "iOS/OS X",
+"Read only iCalendar link(s)" => "Collegamento(i) iCalendar sola lettura",
"Users" => "Utenti",
"select users" => "seleziona utenti",
"Editable" => "Modificabile",
diff --git a/apps/calendar/l10n/vi.php b/apps/calendar/l10n/vi.php
new file mode 100644
index 00000000000..059b89e1635
--- /dev/null
+++ b/apps/calendar/l10n/vi.php
@@ -0,0 +1,135 @@
+<?php $TRANSLATIONS = array(
+"No calendars found." => "Không tìm thấy lịch.",
+"No events found." => "Không tìm thấy sự kiện nào",
+"Wrong calendar" => "Sai lịch",
+"New Timezone:" => "Múi giờ mới :",
+"Timezone changed" => "Thay đổi múi giờ",
+"Invalid request" => "Yêu cầu không hợp lệ",
+"Calendar" => "Lịch",
+"ddd" => "ddd",
+"ddd M/d" => "ddd M/d",
+"dddd M/d" => "dddd M/d",
+"MMMM yyyy" => "MMMM yyyy",
+"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}" => "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
+"dddd, MMM d, yyyy" => "dddd, MMM d, yyyy",
+"Birthday" => "Ngày sinh nhật",
+"Business" => "Công việc",
+"Call" => "Số điện thoại",
+"Clients" => "Máy trạm",
+"Holidays" => "Ngày lễ",
+"Ideas" => "Ý tưởng",
+"Jubilee" => "Lễ kỷ niệm",
+"Meeting" => "Hội nghị",
+"Other" => "Khác",
+"Personal" => "Cá nhân",
+"Projects" => "Dự án",
+"Questions" => "Câu hỏi",
+"Work" => "Công việc",
+"New Calendar" => "Lịch mới",
+"Does not repeat" => "Không lặp lại",
+"Daily" => "Hàng ngày",
+"Weekly" => "Hàng tuần",
+"Every Weekday" => "Mỗi ngày trong tuần",
+"Bi-Weekly" => "Hai tuần một lần",
+"Monthly" => "Hàng tháng",
+"Yearly" => "Hàng năm",
+"never" => "không thay đổi",
+"by occurrences" => "bởi xuất hiện",
+"by date" => "bởi ngày",
+"by monthday" => "bởi ngày trong tháng",
+"by weekday" => "bởi ngày trong tuần",
+"Monday" => "Thứ 2",
+"Tuesday" => "Thứ 3",
+"Wednesday" => "Thứ 4",
+"Thursday" => "Thứ 5",
+"Friday" => "Thứ ",
+"Saturday" => "Thứ 7",
+"Sunday" => "Chủ nhật",
+"events week of month" => "sự kiện trong tuần của tháng",
+"first" => "đầu tiên",
+"second" => "Thứ hai",
+"third" => "Thứ ba",
+"fourth" => "Thứ tư",
+"fifth" => "Thứ năm",
+"January" => "Tháng 1",
+"February" => "Tháng 2",
+"March" => "Tháng 3",
+"April" => "Tháng 4",
+"May" => "Tháng 5",
+"June" => "Tháng 6",
+"July" => "Tháng 7",
+"August" => "Tháng 8",
+"September" => "Tháng 9",
+"October" => "Tháng 10",
+"November" => "Tháng 11",
+"December" => "Tháng 12",
+"by events date" => "Theo ngày tháng sự kiện",
+"by weeknumber(s)" => "số tuần",
+"by day and month" => "ngày, tháng",
+"Date" => "Ngày",
+"Cal." => "Cal.",
+"All day" => "Tất cả các ngày",
+"Title" => "Tiêu đề",
+"From Date" => "Từ ngày",
+"From Time" => "Từ thời gian",
+"To Date" => "Tới ngày",
+"To Time" => "Tới thời gian",
+"The event ends before it starts" => "Sự kiện này kết thúc trước khi nó bắt đầu",
+"Week" => "Tuần",
+"Month" => "Tháng",
+"List" => "Danh sách",
+"Today" => "Hôm nay",
+"Calendars" => "Lịch",
+"There was a fail, while parsing the file." => "Có một thất bại, trong khi phân tích các tập tin.",
+"Choose active calendars" => "Chọn lịch hoạt động",
+"Your calendars" => "Lịch của bạn",
+"CalDav Link" => "Liên kết CalDav ",
+"Shared calendars" => "Chia sẻ lịch",
+"No shared calendars" => "Không chia sẻ lcihj",
+"Share Calendar" => "Chia sẻ lịch",
+"Download" => "Tải về",
+"Edit" => "Chỉnh sửa",
+"Delete" => "Xóa",
+"shared with you by" => "Chia sẻ bởi",
+"New calendar" => "Lịch mới",
+"Edit calendar" => "sửa Lịch",
+"Displayname" => "Hiển thị tên",
+"Active" => "Kích hoạt",
+"Calendar color" => "Màu lịch",
+"Save" => "Lưu",
+"Submit" => "Submit",
+"Cancel" => "Hủy",
+"Edit an event" => "Sửa sự kiện",
+"Share" => "Chia sẻ",
+"Title of the Event" => "Tên sự kiện",
+"Category" => "Danh mục",
+"All Day Event" => "Sự kiện trong ngày",
+"From" => "Từ",
+"To" => "Tới",
+"Advanced options" => "Tùy chọn nâng cao",
+"Location" => "Nơi",
+"Location of the Event" => "Nơi tổ chức sự kiện",
+"Description" => "Mô tả",
+"Description of the Event" => "Mô tả sự kiện",
+"Repeat" => "Lặp lại",
+"Advanced" => "Nâng cao",
+"Select weekdays" => "Chọn ngày trong tuần",
+"Select days" => "Chọn ngày",
+"and the events day of year." => "và sự kiện của ngày trong năm",
+"and the events day of month." => "và sự kiện của một ngày trong năm",
+"Select months" => "Chọn tháng",
+"Select weeks" => "Chọn tuần",
+"and the events week of year." => "và sự kiện của tuần trong năm.",
+"create a new calendar" => "Tạo lịch mới",
+"Name of new calendar" => "Tên lịch mới",
+"Close Dialog" => "Đóng hộp thoại",
+"Create a new event" => "Tạo một sự kiện mới",
+"View an event" => "Xem một sự kiện",
+"No categories selected" => "Không danh sách nào được chọn",
+"of" => "của",
+"at" => "tại",
+"Timezone" => "Múi giờ",
+"Check always for changes of the timezone" => "Luôn kiểm tra múi giờ",
+"24h" => "24h",
+"12h" => "12h"
+);
diff --git a/apps/calendar/lib/calendar.php b/apps/calendar/lib/calendar.php
index 128b55c48e9..7778242464c 100644
--- a/apps/calendar/lib/calendar.php
+++ b/apps/calendar/lib/calendar.php
@@ -267,8 +267,42 @@ class OC_Calendar_Calendar{
'url' => OCP\Util::linkTo('calendar', 'ajax/events.php').'?calendar_id='.$calendar['id'],
'backgroundColor' => $calendar['calendarcolor'],
'borderColor' => '#888',
- 'textColor' => 'black',
+ 'textColor' => self::generateTextColor($calendar['calendarcolor']),
'cache' => true,
);
}
+
+ /*
+ * @brief checks if a calendar name is available for a user
+ * @param string $calendarname
+ * @param string $userid
+ * @return boolean
+ */
+ public static function isCalendarNameavailable($calendarname, $userid){
+ $calendars = self::allCalendars($userid);
+ foreach($calendars as $calendar){
+ if($calendar['displayname'] == $calendarname){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * @brief generates the text color for the calendar
+ * @param string $calendarcolor rgb calendar color code in hex format (with or without the leading #)
+ * (this function doesn't pay attention on the alpha value of rgba color codes)
+ * @return boolean
+ */
+ public static function generateTextColor($calendarcolor){
+ if(substr_count($calendarcolor, '#') == 1){
+ $calendarcolor = substr($calendarcolor,1);
+ }
+ $red = hexdec(substr($calendarcolor,0,2));
+ $green = hexdec(substr($calendarcolor,2,2));
+ $blue = hexdec(substr($calendarcolor,2,2));
+ //recommendation by W3C
+ $computation = ((($red * 299) + ($green * 587) + ($blue * 114)) / 1000);
+ return ($computation > 130)?'#000000':'#FAFAFA';
+ }
}
diff --git a/apps/calendar/lib/connector_sabre.php b/apps/calendar/lib/connector_sabre.php
index 263fb7ffde5..8eea06da7e2 100644
--- a/apps/calendar/lib/connector_sabre.php
+++ b/apps/calendar/lib/connector_sabre.php
@@ -105,6 +105,9 @@ class OC_Connector_Sabre_CalDAV extends Sabre_CalDAV_Backend_Abstract {
if(!isset($newValues['timezone'])) $newValues['timezone'] = null;
if(!isset($newValues['calendarorder'])) $newValues['calendarorder'] = 0;
if(!isset($newValues['calendarcolor'])) $newValues['calendarcolor'] = null;
+ if(!is_null($newValues['calendarcolor']) && strlen($newValues['calendarcolor']) == 9){
+ $newValues['calendarcolor'] = substr($newValues['calendarcolor'], 0, 7);
+ }
return OC_Calendar_Calendar::addCalendarFromDAVData($principalUri,$calendarUri,$newValues['displayname'],$newValues['components'],$newValues['timezone'],$newValues['calendarorder'],$newValues['calendarcolor']);
}
@@ -192,7 +195,10 @@ class OC_Connector_Sabre_CalDAV extends Sabre_CalDAV_Backend_Abstract {
if(!isset($newValues['timezone'])) $newValues['timezone'] = null;
if(!isset($newValues['calendarorder'])) $newValues['calendarorder'] = null;
if(!isset($newValues['calendarcolor'])) $newValues['calendarcolor'] = null;
-
+ if(!is_null($newValues['calendarcolor']) && strlen($newValues['calendarcolor']) == 9){
+ $newValues['calendarcolor'] = substr($newValues['calendarcolor'], 0, 7);
+ }
+
OC_Calendar_Calendar::editCalendar($calendarId,$newValues['displayname'],null,$newValues['timezone'],$newValues['calendarorder'],$newValues['calendarcolor']);
return true;
diff --git a/apps/calendar/lib/import.php b/apps/calendar/lib/import.php
new file mode 100644
index 00000000000..d36891cb2b9
--- /dev/null
+++ b/apps/calendar/lib/import.php
@@ -0,0 +1,334 @@
+<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev@georgswebsite.de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+/*
+ * This class does import and converts all times to the users current timezone
+ */
+class OC_Calendar_Import{
+ /*
+ * @brief counts the absolute number of parsed elements
+ */
+ private $abscount;
+
+ /*
+ * @brief var saves if the percentage should be saved with OC_Cache
+ */
+ private $cacheprogress;
+
+ /*
+ * @brief Sabre_VObject_Component_VCalendar object - for documentation see http://code.google.com/p/sabredav/wiki/Sabre_VObject_Component_VCalendar
+ */
+ private $calobject;
+
+ /*
+ * @brief var counts the number of imported elements
+ */
+ private $count;
+
+ /*
+ * @brief var to check if errors happend while initialization
+ */
+ private $error;
+
+ /*
+ * @brief var saves the ical string that was submitted with the __construct function
+ */
+ private $ical;
+
+ /*
+ * @brief calendar id for import
+ */
+ private $id;
+
+ /*
+ * @brief var saves the percentage of the import's progress
+ */
+ private $progress;
+
+ /*
+ * @brief var saves the key for the percentage of the import's progress
+ */
+ private $progresskey;
+
+ /*
+ * @brief var saves the timezone the events shell converted to
+ */
+ private $tz;
+
+ /*
+ * @brief var saves the userid
+ */
+ private $userid;
+
+ /*
+ * public methods
+ */
+
+ /*
+ * @brief does general initialization for import object
+ * @param string $calendar content of ical file
+ * @param string $tz timezone of the user
+ * @return boolean
+ */
+ public function __construct($ical){
+ $this->error = null;
+ $this->ical = $ical;
+ $this->abscount = 0;
+ $this->count = 0;
+ try{
+ $this->calobject = OC_VObject::parse($this->ical);
+ }catch(Exception $e){
+ //MISSING: write some log
+ $this->error = true;
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * @brief imports a calendar
+ * @return boolean
+ */
+ public function import(){
+ if(!$this->isValid()){
+ return false;
+ }
+ $numofcomponents = count($this->calobject->getComponents());
+ foreach($this->calobject->getComponents() as $object){
+ if(!($object instanceof Sabre_VObject_Component_VEvent) && !($object instanceof Sabre_VObject_Component_VJournal) && !($object instanceof Sabre_VObject_Component_VTodo)){
+ continue;
+ }
+ $dtend = OC_Calendar_Object::getDTEndFromVEvent($object);
+ $object->DTSTART->getDateTime()->setTimezone(new DateTimeZone($this->tz));
+ $object->DTEND->setDateTime($dtend->getDateTime(), $object->DTSTART->getDateType());
+ $object->DTEND->getDateTime()->setTimezone(new DateTimeZone($this->tz));
+ $vcalendar = $this->createVCalendar($object->serialize());
+ $insertid = OC_Calendar_Object::add($this->id, $vcalendar);
+ $this->abscount++;
+ if($this->isDuplicate($insertid)){
+ OC_Calendar_Object::delete($insertid);
+ }else{
+ $this->count++;
+ }
+ $this->updateProgress(intval(($this->abscount / $numofcomponents)*100));
+ }
+ OC_Cache::remove($this->progresskey);
+ return true;
+ }
+
+ /*
+ * @brief sets the timezone
+ * @return boolean
+ */
+ public function setTimeZone($tz){
+ $this->tz = $tz;
+ return true;
+ }
+
+ /*
+ * @brief sets the progresskey
+ * @return boolean
+ */
+ public function setProgresskey($progresskey){
+ $this->progresskey = $progresskey;
+ return true;
+ }
+
+ /*
+ * @brief checks if something went wrong while initialization
+ * @return boolean
+ */
+ public function isValid(){
+ if(is_null($this->error)){
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * @brief returns the percentage of progress
+ * @return integer
+ */
+ public function getProgress(){
+ return $this->progress;
+ }
+
+ /*
+ * @brief enables the cache for the percentage of progress
+ * @return boolean
+ */
+ public function enableProgressCache(){
+ $this->cacheprogress = true;
+ return true;
+ }
+
+ /*
+ * @brief disables the cache for the percentage of progress
+ * @return boolean
+ */
+ public function disableProgressCache(){
+ $this->cacheprogress = false;
+ return false;
+ }
+
+ /*
+ * @brief generates a new calendar name
+ * @return string
+ */
+ public function createCalendarName(){
+ $calendars = OC_Calendar_Calendar::allCalendars($this->userid);
+ $calendarname = $guessedcalendarname = !is_null($this->guessCalendarName())?($this->guessCalendarName()):(OC_Calendar_App::$l10n->t('New Calendar'));
+ $i = 1;
+ while(!OC_Calendar_Calendar::isCalendarNameavailable($calendarname, $this->userid)){
+ $calendarname = $guessedcalendarname . ' (' . $i . ')';
+ $i++;
+ }
+ return $calendarname;
+ }
+
+ /*
+ * @brief generates a new calendar color
+ * @return string
+ */
+ public function createCalendarColor(){
+ if(is_null($this->guessCalendarColor())){
+ return '#9fc6e7';
+ }
+ return $this->guessCalendarColor();
+ }
+
+ /*
+ * @brief sets the id for the calendar
+ * @param integer $id of the calendar
+ * @return boolean
+ */
+ public function setCalendarID($id){
+ $this->id = $id;
+ return true;
+ }
+
+ /*
+ * @brief sets the userid to import the calendar
+ * @param string $id of the user
+ * @return boolean
+ */
+ public function setUserID($userid){
+ $this->userid = $userid;
+ return true;
+ }
+
+ /*
+ * @brief returns the private
+ * @param string $id of the user
+ * @return boolean
+ */
+ public function getCount(){
+ return $this->count;
+ }
+
+ /*
+ * private methods
+ */
+
+ /*
+ * @brief generates an unique ID
+ * @return string
+ */
+ //private function createUID(){
+ // return substr(md5(rand().time()),0,10);
+ //}
+
+ /*
+ * @brief checks is the UID is already in use for another event
+ * @param string $uid uid to check
+ * @return boolean
+ */
+ //private function isUIDAvailable($uid){
+ //
+ //}
+
+ /*
+ * @brief generates a proper VCalendar string
+ * @param string $vobject
+ * @return string
+ */
+ private function createVCalendar($vobject){
+ if(is_object($vobject)){
+ $vobject = @$vobject->serialize();
+ }
+ $vcalendar = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:ownCloud Calendar " . OCP\App::getAppVersion('calendar') . "\n";
+ $vcalendar .= $vobject;
+ $vcalendar .= "END:VCALENDAR";
+ return $vcalendar;
+ }
+
+ /*
+ * @brief checks if an event already exists in the user's calendars
+ * @param integer $insertid id of the new object
+ * @return boolean
+ */
+ private function isDuplicate($insertid){
+ $newobject = OC_Calendar_Object::find($insertid);
+ $stmt = OCP\DB::prepare('SELECT COUNT(*) as count FROM *PREFIX*calendar_objects WHERE objecttype=? AND startdate=? AND enddate=? AND repeating=? AND summary=? AND calendardata=?');
+ $result = $stmt->execute(array($newobject['objecttype'],$newobject['startdate'],$newobject['enddate'],$newobject['repeating'],$newobject['summary'],$newobject['calendardata']));
+ $result = $result->fetchRow();
+ if($result['count'] >= 2){
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * @brief updates the progress var
+ * @param integer $percentage
+ * @return boolean
+ */
+ private function updateProgress($percentage){
+ $this->progress = $percentage;
+ if($this->cacheprogress){
+ OC_Cache::set($this->progresskey, $this->progress, 300);
+ }
+ return true;
+ }
+
+ /*
+ * public methods for (pre)rendering of X-... Attributes
+ */
+
+ /*
+ * @brief guesses the calendar color
+ * @return mixed - string or boolean
+ */
+ public function guessCalendarColor(){
+ if(!is_null($this->calobject->__get('X-APPLE-CALENDAR-COLOR'))){
+ return $this->calobject->__get('X-APPLE-CALENDAR-COLOR');
+ }
+ return null;
+ }
+
+ /*
+ * @brief guesses the calendar description
+ * @return mixed - string or boolean
+ */
+ public function guessCalendarDescription(){
+ if(!is_null($this->calobject->__get('X-WR-CALDESC'))){
+ return $this->calobject->__get('X-WR-CALDESC');
+ }
+ return null;
+ }
+
+ /*
+ * @brief guesses the calendar name
+ * @return mixed - string or boolean
+ */
+ public function guessCalendarName(){
+ if(!is_null($this->calobject->__get('X-WR-CALNAME'))){
+ return $this->calobject->__get('X-WR-CALNAME');
+ }
+ return null;
+ }
+}
diff --git a/apps/calendar/templates/part.import.php b/apps/calendar/templates/part.import.php
index 70ff9612157..2ce3cc34239 100644
--- a/apps/calendar/templates/part.import.php
+++ b/apps/calendar/templates/part.import.php
@@ -1,30 +1,58 @@
-<div id="calendar_import_dialog" title="<?php echo $l->t("Import a calendar file"); ?>">
-<div id="form_container">
-<input type="hidden" id="filename" value="<?php echo $_['filename'];?>">
-<input type="hidden" id="path" value="<?php echo $_['path'];?>">
-<input type="hidden" id="progresskey" value="<?php echo rand() ?>">
-<p style="text-align:center;"><b><?php echo $l->t('Please choose the calendar'); ?></b></p>
-<select style="width:100%;" id="calendar" name="calendar">
<?php
+//Prerendering for iCalendar file
+$file = OC_Filesystem::file_get_contents($_['path'] . '/' . $_['filename']);
+if(!$file){
+ OCP\JSON::error(array('error'=>'404'));
+}
+$import = new OC_Calendar_Import($file);
+$import->setUserID(OCP\User::getUser());
+$newcalendarname = strip_tags($import->createCalendarName());
+$guessedcalendarname = strip_tags($import->guessCalendarName());
+$calendarcolor = strip_tags($import->createCalendarColor());
+//loading calendars for select box
$calendar_options = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser());
$calendar_options[] = array('id'=>'newcal', 'displayname'=>$l->t('create a new calendar'));
-for($i = 0;$i<count($calendar_options);$i++){
- $calendar_options[$i]['displayname'] = $calendar_options[$i]['displayname'];
-}
-echo OCP\html_select_options($calendar_options, $calendar_options[0]['id'], array('value'=>'id', 'label'=>'displayname'));
+$defaultcolors = OC_Calendar_Calendar::getCalendarColorOptions();
?>
-</select>
-<div id="newcalform" style="display: none;">
- <input type="text" style="width: 97%;" placeholder="<?php echo $l->t('Name of new calendar'); ?>" id="newcalendar" name="newcalendar">
-</div>
-<input type="button" value="<?php echo $l->t("Import");?>!" id="startimport">
-</div>
-<div id="progressbar_container" style="display: none">
-<p style="text-align:center;"><b><?php echo $l->t('Importing calendar'); ?></b></p>
-<div id="progressbar"></div>
-<div id="import_done" style="display: none;">
-<p style="text-align:center;"><b><?php echo $l->t('Calendar imported successfully'); ?></b></p>
-<input type="button" value="<?php echo $l->t('Close Dialog'); ?>" id="import_done_button">
+<div id="calendar_import_dialog" title="<?php echo $l->t("Import a calendar file");?>">
+<div id="calendar_import_form">
+ <form>
+ <input type="hidden" id="calendar_import_filename" value="<?php echo $_['filename'];?>">
+ <input type="hidden" id="calendar_import_path" value="<?php echo $_['path'];?>">
+ <input type="hidden" id="calendar_import_progresskey" value="<?php echo rand() ?>">
+ <input type="hidden" id="calendar_import_availablename" value="<?php echo $newcalendarname ?>">
+ <div id="calendar_import_form_message"><?php echo $l->t('Please choose a calendar'); ?></div>
+ <select style="width:100%;" id="calendar_import_calendar" name="calendar_import_calendar">
+ <?php
+ for($i = 0;$i<count($calendar_options);$i++){
+ $calendar_options[$i]['displayname'] = $calendar_options[$i]['displayname'];
+ }
+ echo OCP\html_select_options($calendar_options, $calendar_options[0]['id'], array('value'=>'id', 'label'=>'displayname'));
+ ?>
+ </select>
+ <br><br>
+ <div id="calendar_import_newcalform">
+ <input id="calendar_import_newcalendar_color" class="color-picker" type="hidden" size="6" value="<?php echo substr($calendarcolor,1); ?>">
+ <input id="calendar_import_newcalendar" class="" type="text" placeholder="<?php echo $l->t('Name of new calendar'); ?>" value="<?php echo $guessedcalendarname ?>"><br>
+ <div id="calendar_import_defaultcolors">
+ <?php
+ foreach($defaultcolors as $color){
+ echo '<span class="calendar-colorpicker-color" rel="' . $color . '" style="background-color: ' . $color . ';"></span>';
+ }
+ ?>
+ </div>
+ <!--<input id="calendar_import_generatename" type="button" class="button" value="<?php echo $l->t('Take an available name!'); ?>"><br>-->
+ <div id="calendar_import_mergewarning" class="hint"><?php echo $l->t('A Calendar with this name already exists. If you continue anyhow, these calendars will be merged.'); ?></div>
+ </div>
+ <input id="calendar_import_submit" type="button" class="button" value="&raquo; <?php echo $l->t('Import'); ?> &raquo;" id="startimport">
+ <form>
</div>
+<div id="calendar_import_process">
+ <div id="calendar_import_process_message"></div>
+ <div id="calendar_import_progressbar"></div>
+ <br>
+ <div id="calendar_import_status" class="hint"></div>
+ <br>
+ <input id="calendar_import_done" type="button" value="<?php echo $l->t('Close Dialog'); ?>">
</div>
</div> \ No newline at end of file
diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php
deleted file mode 100644
index be924b5db4d..00000000000
--- a/apps/contacts/ajax/loadphoto.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Thomas Tanghus
- * @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-// Check if we are a user
-OCP\JSON::checkLoggedIn();
-OCP\JSON::checkAppEnabled('contacts');
-
-require_once 'loghandler.php';
-
-$id = isset($_GET['id']) ? $_GET['id'] : '';
-$refresh = isset($_GET['refresh']) ? true : false;
-
-if($id == '') {
- bailOut(OC_Contacts_App::$l10n->t('Missing contact id.'));
-}
-
-$checksum = '';
-$vcard = OC_Contacts_App::getContactVCard( $id );
-foreach($vcard->children as $property){
- if($property->name == 'PHOTO') {
- $checksum = md5($property->serialize());
- break;
- }
-}
-
-OCP\JSON::success(array('data' => array('checksum'=>$checksum)));
-
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 927e7309807..ddae27da211 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -125,3 +125,12 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; }
.typelist[type="button"] { float: left; max-width: 10em; border: 0; background-color: #fff; color: #bbb} /* for multiselect */
.typelist[type="button"]:hover { color: #777; } /* for multiselect */
.addresslist { clear: both; font-weight: bold; }
+#ninjahelp { position: absolute; bottom: 0; left: 0; right: 0; padding: 1em; margin: 1em; border: thin solid #eee; border-radius: 5px; background-color: #DBDBDB; opacity: 0.9; }
+#ninjahelp .close { position: absolute; top: 5px; right: 5px; height: 20px; width: 20px; }
+#ninjahelp h2, .help-section h3 { width: 100%; font-weight: bold; text-align: center; }
+#ninjahelp h2 { font-size: 1.4em; }
+.help-section { width: 45%; min-width: 35em; float: left; }
+.help-section h3 { font-size: 1.2em; }
+.help-section dl { width: 100%; float: left; clear: right; margin: 0; padding: 0; cursor: normal; }
+.help-section dt { display: table-cell; clear: left; float: left; width: 35%; margin: 0; padding: 0.2em; text-align: right; text-overflow: ellipsis; vertical-align: text-bottom; font-weight: bold: }
+.help-section dd { display: table-cell; clear: right; float: left; margin: 0; padding: 0.2em; white-space: nowrap; vertical-align: text-bottom; }
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 337f51839dc..4c6c8bf3d93 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -21,27 +21,31 @@ Contacts={
* data: An object that will be passed as argument to the timeouthandler and clickhandler functions.
*/
notify:function(params) {
- var notifier = $('#notification');
- notifier.text(params.message);
- notifier.fadeIn();
+ self = this;
+ if(!self.notifier) {
+ self.notifier = $('#notification');
+ }
+ self.notifier.text(params.message);
+ self.notifier.fadeIn();
+ self.notifier.on('click', function() { $(this).fadeOut();});
var timer = setTimeout(function() {
- notifier.fadeOut();
+ self.notifier.fadeOut();
if(params.timeouthandler && $.isFunction(params.timeouthandler)) {
- params.timeouthandler(notifier.data(dataid));
- notifier.off('click');
- notifier.data(dataid, null);
+ params.timeouthandler(self.notifier.data(dataid));
+ self.notifier.off('click');
+ self.notifier.removeData(dataid);
}
}, params.timeout && $.isNumeric(params.timeout) ? parseInt(params.timeout)*1000 : 10000);
var dataid = timer.toString();
if(params.data) {
- notifier.data(dataid, params.data);
+ self.notifier.data(dataid, params.data);
}
if(params.clickhandler && $.isFunction(params.clickhandler)) {
- notifier.on('click', function() {
+ self.notifier.on('click', function() {
clearTimeout(timer);
- notifier.off('click');
- params.clickhandler(notifier.data(dataid));
- notifier.data(dataid, null);
+ self.notifier.off('click');
+ params.clickhandler(self.notifier.data(dataid));
+ self.notifier.removeData(dataid);
});
}
},
@@ -218,11 +222,7 @@ Contacts={
var item = $('.contacts li[data-id="'+Contacts.UI.Card.id+'"]').detach();
$(item).find('a').html(name);
Contacts.UI.Card.fn = name;
- Contacts.UI.Contacts.insertContact({
- contactlist:$('#contacts ul[data-id="'+Contacts.UI.Card.bookid+'"]'),
- contacts:$('#contacts ul[data-id="'+Contacts.UI.Card.bookid+'"] li'),
- contact:item,
- });
+ Contacts.UI.Contacts.insertContact({contact:item});
Contacts.UI.Contacts.scrollTo(Contacts.UI.Card.id);
});
@@ -295,16 +295,6 @@ Contacts={
$('#contacts_propertymenu_dropdown a').keydown(propertyMenuItem);
},
Card:{
- id:'',
- fn:'',
- fullname:'',
- shortname:'',
- famname:'',
- givname:'',
- addname:'',
- honpre:'',
- honsuf:'',
- data:undefined,
update:function(params) { // params {cid:int, aid:int}
if(!params) { params = {}; }
$('#contacts li,#contacts h3').removeClass('active');
@@ -321,10 +311,11 @@ Contacts={
newid = parseInt($('#contacts').find('li[data-bookid="'+bookid+'"]').first().data('id'));
} else if(parseInt(params.cid) && !parseInt(params.aid)) {
newid = parseInt(params.cid);
- var listitem = $('#contacts li[data-id="'+newid+'"]');
+ var listitem = Contacts.UI.Contacts.getContact(newid); //$('#contacts li[data-id="'+newid+'"]');
console.log('Is contact in list? ' + listitem.length);
if(listitem.length) {
- bookid = parseInt($('#contacts li[data-id="'+newid+'"]').data('bookid'));
+ //bookid = parseInt($('#contacts li[data-id="'+newid+'"]').data('bookid'));
+ bookid = parseInt(Contacts.UI.Contacts.getContact(newid).data('bookid'));
} else { // contact isn't in list yet.
bookid = 'unknown';
}
@@ -412,19 +403,7 @@ Contacts={
$.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':id},function(jsondata){
if(jsondata.status == 'success'){
Contacts.UI.Card.loadContact(jsondata.data, aid);
- $('#contacts .active').removeClass('active');
- var item = $('<li data-id="'+jsondata.data.id+'" class="active"><a href="index.php?id='+jsondata.data.id+'" style="background: url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+jsondata.data.id+') no-repeat scroll 0% 0% transparent;">'+Contacts.UI.Card.fn+'</a></li>');
- var added = false;
- $('#contacts ul[data-id="'+aid+'"] li').each(function(){
- if ($(this).text().toLowerCase() > Contacts.UI.Card.fn.toLowerCase()) {
- $(this).before(item).fadeIn('fast');
- added = true;
- return false;
- }
- });
- if(!added) {
- $('#contacts ul[data-id="'+aid+'"]').append(item);
- }
+ var item = Contacts.UI.Contacts.insertContact({data:jsondata.data});
if(isnew) { // add some default properties
Contacts.UI.Card.addProperty('EMAIL');
Contacts.UI.Card.addProperty('TEL');
@@ -461,9 +440,14 @@ Contacts={
}
},
delayedDelete:function() {
+ /* TODO:
+ $(window).unload(function() {
+ deleteFilesInQueue();
+ });
+ */
$('#contacts_deletecard').tipsy('hide');
var newid = '', bookid;
- var curlistitem = $('#contacts li[data-id="'+Contacts.UI.Card.id+'"]');
+ var curlistitem = Contacts.UI.Contacts.getContact(this.id);
curlistitem.removeClass('active');
var newlistitem = curlistitem.prev('li');
if(!newlistitem) {
@@ -474,19 +458,21 @@ Contacts={
newid = newlistitem.data('id');
bookid = newlistitem.data('bookid');
}
- $('#rightcontent').data('id',newid);
- this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
- this.data = undefined;
+ $('#rightcontent').data('id', newid);
+
+ with(this) {
+ delete id; delete fn; delete fullname; delete shortname; delete famname;
+ delete givname; delete addname; delete honpre; delete honsuf; delete data;
+ }
- if($('.contacts li').length > 0) { // Load first in list.
+ if($('.contacts li').length > 0) {
Contacts.UI.Card.update({cid:newid, aid:bookid});
} else {
// load intro page
$.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){
if(jsondata.status == 'success'){
id = '';
- $('#rightcontent').data('id','');
- $('#rightcontent').html(jsondata.data.page);
+ $('#rightcontent').html(jsondata.data.page).removeData('id');
}
else{
OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
@@ -526,21 +512,22 @@ Contacts={
this.loadAddresses();
this.loadSingleProperties();
Contacts.UI.loadListHandlers();
+ var note = $('#note');
if(this.data.NOTE) {
- $('#note').data('checksum', this.data.NOTE[0]['checksum']);
- var note = $('#note').find('textarea');
+ note.data('checksum', this.data.NOTE[0]['checksum']);
+ var textarea = note.find('textarea');
var txt = this.data.NOTE[0]['value'];
var nheight = txt.split('\n').length > 4 ? txt.split('\n').length+2 : 5;
- note.css('min-height', nheight+'em');
- note.attr('rows', nheight);
- note.val(txt);
- $('#note').show();
- note.expandingTextarea();
+ textarea.css('min-height', nheight+'em');
+ textarea.attr('rows', nheight);
+ textarea.val(txt);
+ note.show();
+ textarea.expandingTextarea();
$('#contacts_propertymenu_dropdown a[data-type="NOTE"]').parent().hide();
} else {
- $('#note').data('checksum', '');
- $('#note').find('textarea').val('');
- $('#note').hide();
+ note.removeData('checksum');
+ note.find('textarea').val('');
+ note.hide();
$('#contacts_propertymenu_dropdown a[data-type="NOTE"]').parent().show();
}
},
@@ -566,10 +553,11 @@ Contacts={
var val = $.datepicker.parseDate('yy-mm-dd', value.substring(0, 10));
value = $.datepicker.formatDate('dd-mm-yy', val);
}
- $('#contact_identity').find('#'+propname.toLowerCase()).val(value);
- $('#contact_identity').find('#'+propname.toLowerCase()+'_value').data('checksum', checksum);
- $('#contact_identity').find('#'+propname.toLowerCase()+'_label').show();
- $('#contact_identity').find('#'+propname.toLowerCase()+'_value').show();
+ var identcontainer = $('#contact_identity');
+ identcontainer.find('#'+propname.toLowerCase()).val(value);
+ identcontainer.find('#'+propname.toLowerCase()+'_value').data('checksum', checksum);
+ identcontainer.find('#'+propname.toLowerCase()+'_label').show();
+ identcontainer.find('#'+propname.toLowerCase()+'_value').show();
} else {
$('#contacts_propertymenu_dropdown a[data-type="'+propname+'"]').parent().show();
}
@@ -584,8 +572,12 @@ Contacts={
$(this).find('input').val('');
}
});
- this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = '';
- var narray = undefined;
+
+ with(this) {
+ delete fn; delete fullname; delete givname; delete famname;
+ delete addname; delete honpre; delete honsuf;
+ }
+
if(this.data.FN) {
this.fn = this.data.FN[0]['value'];
}
@@ -769,17 +761,9 @@ Contacts={
},
addProperty:function(type){
switch (type) {
- case 'PHOTO':
- this.loadPhoto(true);
- $('#file_upload_form').show();
- $('#contacts_propertymenu_dropdown a[data-type="'+type+'"]').parent().hide();
- $('#file_upload_start').trigger('click');
- break;
case 'NOTE':
- $('#note').show();
$('#contacts_propertymenu_dropdown a[data-type="'+type+'"]').parent().hide();
- $('#note').find('textarea').expandingTextarea();
- $('#note').find('textarea').focus();
+ $('#note').find('textarea').expandingTextarea().show().focus();
break;
case 'EMAIL':
if($('#emaillist>li').length == 1) {
@@ -834,8 +818,7 @@ Contacts={
}
} else {
$('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide();
- $('dl dd[data-element="'+proptype+'"]').data('checksum', '');
- $('dl dd[data-element="'+proptype+'"]').find('input').val('');
+ $('dl dd[data-element="'+proptype+'"]').data('checksum', '').find('input').val('');
}
$('#contacts_propertymenu_dropdown a[data-type="'+proptype+'"]').parent().show();
Contacts.UI.loading(obj, false);
@@ -862,14 +845,14 @@ Contacts={
}
}
},
- editName:function(){
+ editName:function() {
var params = {id: this.id};
/* Initialize the name edit dialog */
- if($('#edit_name_dialog').dialog('isOpen') == true){
+ if($('#edit_name_dialog').dialog('isOpen') == true) {
$('#edit_name_dialog').dialog('moveToTop');
- }else{
- $.getJSON(OC.filePath('contacts', 'ajax', 'editname.php'),{id: this.id},function(jsondata){
- if(jsondata.status == 'success'){
+ } else {
+ $.getJSON(OC.filePath('contacts', 'ajax', 'editname.php'),{id: this.id},function(jsondata) {
+ if(jsondata.status == 'success') {
$('body').append('<div id="name_dialog"></div>');
$('#name_dialog').html(jsondata.data.page).find('#edit_name_dialog' ).dialog({
modal: true,
@@ -941,10 +924,11 @@ Contacts={
loadAddresses:function(){
$('#addresses').hide();
$('#addressdisplay dl.propertycontainer').remove();
+ var addresscontainer = $('#addressdisplay');
for(var adr in this.data.ADR) {
- $('#addressdisplay dl').first().clone().insertAfter($('#addressdisplay dl').last()).show();
- $('#addressdisplay dl').last().removeClass('template').addClass('propertycontainer');
- $('#addressdisplay dl').last().data('checksum', this.data.ADR[adr]['checksum']);
+ addresscontainer.find('dl').first().clone().insertAfter($('#addressdisplay dl').last()).show();
+ addresscontainer.find('dl').last().removeClass('template').addClass('propertycontainer');
+ addresscontainer.find('dl').last().data('checksum', this.data.ADR[adr]['checksum']);
var adrarray = this.data.ADR[adr]['value'];
var adrtxt = '';
if(adrarray[0] && adrarray[0].length > 0) {
@@ -956,7 +940,7 @@ Contacts={
if(adrarray[2] && adrarray[2].length > 0) {
adrtxt = adrtxt + '<li>' + adrarray[2].strip_tags() + '</li>';
}
- if((adrarray[3] && adrarray[5]) && adrarray[3].length > 0 || adrarray[5].length > 0) {
+ if((3 in adrarray && 5 in adrarray) && adrarray[3].length > 0 || adrarray[5].length > 0) {
adrtxt = adrtxt + '<li>' + adrarray[5].strip_tags() + ' ' + adrarray[3].strip_tags() + '</li>';
}
if(adrarray[4] && adrarray[4].length > 0) {
@@ -965,7 +949,7 @@ Contacts={
if(adrarray[6] && adrarray[6].length > 0) {
adrtxt = adrtxt + '<li>' + adrarray[6].strip_tags() + '</li>';
}
- $('#addressdisplay dl').last().find('.addresslist').html(adrtxt);
+ addresscontainer.find('dl').last().find('.addresslist').html(adrtxt);
var types = new Array();
var ttypes = new Array();
for(var param in this.data.ADR[adr]['parameters']) {
@@ -974,12 +958,12 @@ Contacts={
ttypes.push(this.data.ADR[adr]['parameters'][param]);
}
}
- $('#addressdisplay dl').last().find('.adr_type_label').text(types.join('/'));
- $('#addressdisplay dl').last().find('.adr_type').val(ttypes.join(','));
- $('#addressdisplay dl').last().find('.adr').val(adrarray.join(';'));
- $('#addressdisplay dl').last().data('checksum', this.data.ADR[adr]['checksum']);
+ addresscontainer.find('dl').last().find('.adr_type_label').text(types.join('/'));
+ addresscontainer.find('dl').last().find('.adr_type').val(ttypes.join(','));
+ addresscontainer.find('dl').last().find('.adr').val(adrarray.join(';'));
+ addresscontainer.find('dl').last().data('checksum', this.data.ADR[adr]['checksum']);
}
- if($('#addressdisplay dl').length > 1) {
+ if(addresscontainer.find('dl').length > 1) {
$('#addresses').show();
$('#contact_communication').show();
}
@@ -1024,9 +1008,6 @@ Contacts={
close : function(event, ui) {
$(this).dialog('destroy').remove();
$('#address_dialog').remove();
- if(isnew) {
- container.remove();
- }
},
open : function(event, ui) {
$( "#adr_city" ).autocomplete({
@@ -1065,7 +1046,7 @@ Contacts={
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
}
});
- $( "#adr_country" ).autocomplete({
+ $('#adr_country').autocomplete({
source: function( request, response ) {
$.ajax({
url: "http://ws.geonames.org/searchJSON",
@@ -1116,15 +1097,23 @@ Contacts={
saveAddress:function(dlg, obj, isnew){
if(isnew) {
container = $('#addressdisplay dl').last();
- obj = $('#addressdisplay dl:last-child').find('input').first();
+ obj = container.find('input').first();
} else {
checksum = Contacts.UI.checksumFor(obj);
container = Contacts.UI.propertyContainerFor(obj);
}
- var adr = new Array($(dlg).find('#adr_pobox').val().strip_tags(),$(dlg).find('#adr_extended').val().strip_tags(),$(dlg).find('#adr_street').val().strip_tags(),$(dlg).find('#adr_city').val().strip_tags(),$(dlg).find('#adr_region').val().strip_tags(),$(dlg).find('#adr_zipcode').val().strip_tags(),$(dlg).find('#adr_country').val().strip_tags());
- $(container).find('.adr').val(adr.join(';'));
- $(container).find('.adr_type').val($(dlg).find('#adr_type').val());
- $(container).find('.adr_type_label').html(t('contacts',ucwords($(dlg).find('#adr_type').val().toLowerCase())));
+ var adr = new Array(
+ $(dlg).find('#adr_pobox').val().strip_tags(),
+ $(dlg).find('#adr_extended').val().strip_tags(),
+ $(dlg).find('#adr_street').val().strip_tags(),
+ $(dlg).find('#adr_city').val().strip_tags(),
+ $(dlg).find('#adr_region').val().strip_tags(),
+ $(dlg).find('#adr_zipcode').val().strip_tags(),
+ $(dlg).find('#adr_country').val().strip_tags()
+ );
+ container.find('.adr').val(adr.join(';'));
+ container.find('.adr_type').val($(dlg).find('#adr_type').val());
+ container.find('.adr_type_label').html(t('contacts',ucwords($(dlg).find('#adr_type').val().toLowerCase())));
Contacts.UI.Card.saveProperty($(container).find('input').first());
var adrtxt = '';
if(adr[0].length > 0) {
@@ -1145,7 +1134,7 @@ Contacts={
if(adr[6].length > 0) {
adrtxt = adrtxt + '<li>' + adr[6] + '</li>';
}
- $(container).find('.addresslist').html(adrtxt);
+ container.find('.addresslist').html(adrtxt);
},
uploadPhoto:function(filelist) {
if(!filelist) {
@@ -1172,24 +1161,25 @@ Contacts={
form.submit();
}
},
- loadPhotoHandlers:function(){
- $('#phototools li a').tipsy('hide');
- $('#phototools li a').tipsy();
+ loadPhotoHandlers:function() {
+ var phototools = $('#phototools');
+ phototools.find('li a').tipsy('hide');
+ phototools.find('li a').tipsy();
if(this.data.PHOTO) {
- $('#phototools .delete').click(function() {
+ phototools.find('.delete').click(function() {
$(this).tipsy('hide');
Contacts.UI.Card.deleteProperty($('#contacts_details_photo'), 'single');
$(this).hide();
});
- $('#phototools .edit').click(function() {
+ phototools.find('.edit').click(function() {
$(this).tipsy('hide');
Contacts.UI.Card.editCurrentPhoto();
});
- $('#phototools .delete').show();
- $('#phototools .edit').show();
+ phototools.find('.delete').show();
+ phototools.find('.edit').show();
} else {
- $('#phototools .delete').hide();
- $('#phototools .edit').hide();
+ phototools.find('.delete').hide();
+ phototools.find('.edit').hide();
}
},
cloudPhotoSelected:function(path){
@@ -1210,28 +1200,18 @@ Contacts={
$('#phototools li a').tipsy('hide');
var wrapper = $('#contacts_details_photo_wrapper');
wrapper.addClass('loading').addClass('wait');
-
- var img = new Image();
- $(img).load(function () {
+ delete this.photo;
+ this.photo = new Image();
+ $(this.photo).load(function () {
$('img.contacts_details_photo').remove()
- $(this).addClass('contacts_details_photo').hide();
+ $(this).addClass('contacts_details_photo');
wrapper.removeClass('loading').removeClass('wait');
$(this).insertAfter($('#phototools')).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
Contacts.UI.notify({message:t('contacts','Error loading profile picture.')});
}).attr('src', OC.linkTo('contacts', 'photo.php')+'?id='+self.id+refreshstr);
-
- $.getJSON(OC.filePath('contacts', 'ajax', 'loadphoto.php'),{'id':this.id, 'refresh': refresh},function(jsondata){
- if(jsondata.status == 'success'){
- $('#contacts_details_photo_wrapper').data('checksum', jsondata.data.checksum);
- Contacts.UI.Card.loadPhotoHandlers();
- }
- else{
- OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
- }
- });
- $('#file_upload_form').show();
+ this.loadPhotoHandlers()
},
editCurrentPhoto:function(){
$.getJSON(OC.filePath('contacts', 'ajax', 'currentphoto.php'),{'id':this.id},function(jsondata){
@@ -1285,10 +1265,11 @@ Contacts={
},
addMail:function() {
//alert('addMail');
- $('#emaillist li.template:first-child').clone(true).appendTo($('#emaillist')).show().find('a .tip').tipsy();
- $('#emaillist li.template:last-child').find('select').addClass('contacts_property');
- $('#emaillist li.template:last-child').removeClass('template').addClass('propertycontainer');
- $('#emaillist li:last-child').find('input[type="email"]').focus();
+ var emaillist = $('#emaillist');
+ emaillist.find('li.template:first-child').clone(true).appendTo(emaillist).show().find('a .tip').tipsy();
+ emaillist.find('li.template:last-child').find('select').addClass('contacts_property');
+ emaillist.find('li.template:last-child').removeClass('template').addClass('propertycontainer');
+ emaillist.find('li:last-child').find('input[type="email"]').focus();
return false;
},
loadMails:function() {
@@ -1324,35 +1305,37 @@ Contacts={
return false;
},
addPhone:function() {
- $('#phonelist li.template:first-child').clone(true).appendTo($('#phonelist')); //.show();
- $('#phonelist li.template:last-child').find('select').addClass('contacts_property');
- $('#phonelist li.template:last-child').removeClass('template').addClass('propertycontainer');
- $('#phonelist li:last-child').find('input[type="text"]').focus();
- $('#phonelist li:last-child').find('select').multiselect({
+ var phonelist = $('#phonelist');
+ phonelist.find('li.template:first-child').clone(true).appendTo(phonelist); //.show();
+ phonelist.find('li.template:last-child').find('select').addClass('contacts_property');
+ phonelist.find('li.template:last-child').removeClass('template').addClass('propertycontainer');
+ phonelist.find('li:last-child').find('input[type="text"]').focus();
+ phonelist.find('li:last-child').find('select').multiselect({
noneSelectedText: t('contacts', 'Select type'),
header: false,
selectedList: 4,
classes: 'typelist'
});
- $('#phonelist li:last-child').show();
+ phonelist.find('li:last-child').show();
return false;
},
loadPhones:function() {
$('#phones').hide();
$('#phonelist li.propertycontainer').remove();
+ var phonelist = $('#phonelist');
for(var phone in this.data.TEL) {
this.addPhone();
- $('#phonelist li:last-child').find('select').multiselect('destroy');
- $('#phonelist li:last-child').data('checksum', this.data.TEL[phone]['checksum'])
- $('#phonelist li:last-child').find('input[type="text"]').val(this.data.TEL[phone]['value']);
+ phonelist.find('li:last-child').find('select').multiselect('destroy');
+ phonelist.find('li:last-child').data('checksum', this.data.TEL[phone]['checksum'])
+ phonelist.find('li:last-child').find('input[type="text"]').val(this.data.TEL[phone]['value']);
for(var param in this.data.TEL[phone]['parameters']) {
if(param.toUpperCase() == 'PREF') {
- $('#phonelist li:last-child').find('input[type="checkbox"]').attr('checked', 'checked');
+ phonelist.find('li:last-child').find('input[type="checkbox"]').attr('checked', 'checked');
}
else if(param.toUpperCase() == 'TYPE') {
for(ptype in this.data.TEL[phone]['parameters'][param]) {
var pt = this.data.TEL[phone]['parameters'][param][ptype];
- $('#phonelist li:last-child').find('select option').each(function(){
+ phonelist.find('li:last-child').find('select option').each(function(){
//if ($(this).val().toUpperCase() == pt.toUpperCase()) {
if ($.inArray($(this).val().toUpperCase(), pt.toUpperCase().split(',')) > -1) {
$(this).attr('selected', 'selected');
@@ -1361,14 +1344,14 @@ Contacts={
}
}
}
- $('#phonelist li:last-child').find('select').multiselect({
- noneSelectedText: t('contacts', 'Select type'),
- header: false,
- selectedList: 4,
- classes: 'typelist'
- });
+ phonelist.find('li:last-child').find('select').multiselect({
+ noneSelectedText: t('contacts', 'Select type'),
+ header: false,
+ selectedList: 4,
+ classes: 'typelist'
+ });
}
- if($('#phonelist li').length > 1) {
+ if(phonelist.find('li').length > 1) {
$('#phones').show();
$('#contact_communication').show();
}
@@ -1493,7 +1476,25 @@ Contacts={
}
},
Contacts:{
+ contacts:{},
batchnum:50,
+ getContact:function(id) {
+ if(!this.contacts[id]) {
+ this.contacts[id] = $('#contacts li[data-id="'+id+'"]');
+ if(!this.contacts[id]) {
+ self = this;
+ $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':id},function(jsondata){
+ if(jsondata.status == 'success'){
+ self.contacts[id] = self.insertContact({data:jsondata.data});
+ }
+ else{
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
+ });
+ }
+ }
+ return this.contacts[id];
+ },
drop:function(event, ui) {
var dragitem = ui.draggable, droptarget = $(this);
if(dragitem.is('li')) {
@@ -1510,21 +1511,12 @@ Contacts={
$.post(OC.filePath('contacts', 'ajax', 'movetoaddressbook.php'), { ids: dragitem.data('id'), aid: droptarget.data('id') },
function(jsondata){
if(jsondata.status == 'success'){
- // Do some inserting/removing/sorting magic
- var name = $(dragitem).find('a').html();
- var added = false;
- $(droplist).children().each(function(){
- if ($(this).text().toLowerCase() > name.toLowerCase()) {
- $(this).before(dragitem.detach()); //.fadeIn('slow');
- added = true;
- return false;
- }
- });
- if(!added) {
- $(droplist).append(dragitem.detach());
- }
dragitem.attr('data-bookid', droptarget.data('id'))
dragitem.data('bookid', droptarget.data('id'));
+ Contacts.UI.Contacts.insertContact({
+ contactlist:droplist,
+ contact:dragitem.detach()
+ });
Contacts.UI.Contacts.scrollTo(dragitem.data('id'));
} else {
OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
@@ -1541,13 +1533,16 @@ Contacts={
* If 'contactlist' or 'contacts' aren't defined they will be search for based in the properties in 'data'.
*/
insertContact:function(params) {
+ var id, bookid;
if(!params.contactlist) {
// FIXME: Check if contact really exists.
- var bookid = params.data ? params.data.addressbookid : params.contact.data('bookid');
+ bookid = params.data ? params.data.addressbookid : params.contact.data('bookid');
+ id = params.data ? params.data.id : params.contact.data('id');
params.contactlist = $('#contacts ul[data-id="'+bookid+'"]');
}
if(!params.contacts) {
- var bookid = params.data ? params.data.addressbookid : params.contact.data('bookid');
+ bookid = params.data ? params.data.addressbookid : params.contact.data('bookid');
+ id = params.data ? params.data.id : params.contact.data('id');
params.contacts = $('#contacts ul[data-id="'+bookid+'"] li');
}
var contact = params.data
@@ -1567,8 +1562,24 @@ Contacts={
if(!added || !params.contacts) {
params.contactlist.append(contact);
}
+ //this.contacts[id] = contact;
return contact;
},
+ next:function(reverse) {
+ // TODO: Check if we're last-child/first-child and jump to next/prev address book.
+ var curlistitem = $('#contacts li[data-id="'+Contacts.UI.Card.id+'"]');
+ var newlistitem = reverse ? curlistitem.prev('li') : curlistitem.next('li');
+ if(newlistitem) {
+ curlistitem.removeClass('active');
+ Contacts.UI.Card.update({
+ cid:newlistitem.data('id'),
+ aid:newlistitem.data('bookid')
+ });
+ }
+ },
+ previous:function() {
+ this.next(true);
+ },
// Reload the contacts list.
update:function(params){
if(!params) { params = {}; }
@@ -1672,10 +1683,10 @@ Contacts={
},
scrollTo:function(id){
var item = $('#contacts li[data-id="'+id+'"]');
- console.log('scrollTo, found item '+id+'? ' + item.length);
- if(item) {
+ if(item && $.isNumeric(item.offset().top)) {
+ console.log('scrollTo ' + parseInt(item.offset().top));
$('#contacts').animate({
- scrollTop: item.offset().top-40}, 'slow','swing');
+ scrollTop: parseInt(item.offset()).top-40}, 'slow','swing');
}
}
}
@@ -1686,23 +1697,90 @@ $(document).ready(function(){
OCCategories.changed = Contacts.UI.Card.categoriesChanged;
OCCategories.app = 'contacts';
- $('#notification').click(function(){
- $('#notification').fadeOut();
+ $('#chooseaddressbook').on('click keydown', Contacts.UI.Addressbooks.overview);
+ $('#contacts_newcontact').on('click keydown', Contacts.UI.Card.editNew);
+
+ var ninjahelp = $('#ninjahelp');
+
+ ninjahelp.find('.close').on('click keydown',function() {
+ ninjahelp.hide();
});
- $('#chooseaddressbook').click(Contacts.UI.Addressbooks.overview);
- $('#chooseaddressbook').keydown(Contacts.UI.Addressbooks.overview);
+ $(document).on('keyup', function(event) {
+ console.log(event.which + ' ' + event.target.nodeName);
+ if(event.target.nodeName.toUpperCase() != 'BODY'
+ || $('#contacts li').length == 0
+ || !Contacts.UI.Card.id) {
+ return;
+ }
+ /**
+ * To add:
+ * (Shift)n/p: next/prev addressbook
+ * u (85): hide/show leftcontent
+ * f (70): add field
+ */
+ switch(event.which) {
+ case 27: // Esc
+ ninjahelp.hide();
+ break;
+ case 46:
+ if(event.shiftKey) {
+ Contacts.UI.Card.delayedDelete();
+ }
+ break;
+ case 32: // space
+ if(event.shiftKey) {
+ Contacts.UI.Contacts.previous();
+ break;
+ }
+ case 40: // down
+ case 75: // k
+ Contacts.UI.Contacts.next();
+ break;
+ case 65: // a
+ if(event.shiftKey) {
+ // add addressbook
+ Contacts.UI.notImplemented();
+ break;
+ }
+ Contacts.UI.Card.editNew();
+ break;
+ case 38: // up
+ case 74: // j
+ Contacts.UI.Contacts.previous();
+ break;
+ case 78: // n
+ // next addressbook
+ Contacts.UI.notImplemented();
+ break;
+ case 13: // Enter
+ case 79: // o
+ var aid = $('#contacts h3.active').first().data('id');
+ if(aid) {
+ $('#contacts ul[data-id="'+aid+'"]').slideToggle(300);
+ }
+ break;
+ case 80: // p
+ // prev addressbook
+ Contacts.UI.notImplemented();
+ break;
+ case 82: // r
+ Contacts.UI.Contacts.update({cid:Contacts.UI.Card.id});
+ break;
+ case 191: // ?
+ ninjahelp.toggle('fast');
+ break;
+ }
- $('#contacts_newcontact').click(Contacts.UI.Card.editNew);
- $('#contacts_newcontact').keydown(Contacts.UI.Card.editNew);
+ });
- // Load a contact.
+ // Load a contact.
$('.contacts').keydown(function(event) {
if(event.which == 13 || event.which == 32) {
$('.contacts').click();
}
});
- $(document).on('click', '.contacts', function(event){
+ $(document).on('click', '#contacts', function(event){
var $tgt = $(event.target);
if ($tgt.is('li') || $tgt.is('a')) {
var item = $tgt.is('li')?$($tgt):($tgt).parent();
@@ -1931,14 +2009,15 @@ $(document).ready(function(){
$('#selectaddressbook_dialog').dialog('moveToTop');
} else {
$('#dialog_holder').html(jsondata.data.page).ready(function($) {
- $('#selectaddressbook_dialog').dialog({
+ var select_dlg = $('#selectaddressbook_dialog');
+ select_dlg.dialog({
modal: true, height: 'auto', width: 'auto',
buttons: {
'Ok':function() {
- aid = $('#selectaddressbook_dialog').find('input:checked').val();
+ aid = select_dlg.find('input:checked').val();
if(aid == 'new') {
- var displayname = $('#selectaddressbook_dialog').find('input.name').val();
- var description = $('#selectaddressbook_dialog').find('input.desc').val();
+ var displayname = select_dlg.find('input.name').val();
+ var description = select_dlg.find('input.desc').val();
if(!displayname.trim()) {
OC.dialogs.alert(t('contacts', 'The address book name cannot be empty.'), t('contacts', 'Error'));
return false;
diff --git a/apps/contacts/js/loader.js b/apps/contacts/js/loader.js
index 577ad103064..5bca0ab7237 100644
--- a/apps/contacts/js/loader.js
+++ b/apps/contacts/js/loader.js
@@ -78,9 +78,9 @@ Contacts_Import={
}
$(document).ready(function(){
if(typeof FileActions !== 'undefined'){
- FileActions.register('text/vcard','importaddressbook', '', Contacts_Import.importdialog);
+ FileActions.register('text/vcard','importaddressbook', '', Contacts_Import.importdialog);
FileActions.setDefault('text/vcard','importaddressbook');
- FileActions.register('text/x-vcard','importaddressbook', '', Contacts_Import.importdialog);
+ FileActions.register('text/x-vcard','importaddressbook', '', Contacts_Import.importdialog);
FileActions.setDefault('text/x-vcard','importaddressbook');
};
}); \ No newline at end of file
diff --git a/apps/contacts/l10n/it.php b/apps/contacts/l10n/it.php
index 2a5478e6c4b..820104b7774 100644
--- a/apps/contacts/l10n/it.php
+++ b/apps/contacts/l10n/it.php
@@ -1,10 +1,13 @@
<?php $TRANSLATIONS = array(
"Error (de)activating addressbook." => "Errore nel (dis)attivare la rubrica.",
"There was an error adding the contact." => "Si è verificato un errore nell'aggiunta del contatto.",
+"element name is not set." => "il nome dell'elemento non è impostato.",
+"id is not set." => "ID non impostato.",
+"Could not parse contact: " => "Impossibile elaborare il contatto: ",
"Cannot add empty property." => "Impossibile aggiungere una proprietà vuota.",
"At least one of the address fields has to be filled out." => "Deve essere riempito almeno un indirizzo.",
"Trying to add duplicate property: " => "P",
-"Error adding contact property." => "Errore durante l'aggiunta della proprietà del contatto.",
+"Error adding contact property: " => "Errore durante l'aggiunta della proprietà del contatto: ",
"No ID provided" => "Nessun ID fornito",
"Error setting checksum." => "Errore di impostazione del codice di controllo.",
"No categories selected for deletion." => "Nessuna categoria selezionata per l'eliminazione.",
@@ -12,22 +15,23 @@
"No contacts found." => "Nessun contatto trovato.",
"Missing ID" => "ID mancante",
"Error parsing VCard for ID: \"" => "Errore in fase di elaborazione del file VCard per l'ID: \"",
-"Cannot add addressbook with an empty name." => "Impossibile aggiungere una rubrica senza nome.",
-"Error adding addressbook." => "Errore durante l'aggiunta della rubrica.",
-"Error activating addressbook." => "Errore durante l'attivazione della rubrica.",
"No contact ID was submitted." => "Nessun ID di contatto inviato.",
"Error reading contact photo." => "Errore di lettura della foto del contatto.",
"Error saving temporary file." => "Errore di salvataggio del file temporaneo.",
"The loading photo is not valid." => "La foto caricata non è valida.",
-"id is not set." => "ID non impostato.",
"Information about vCard is incorrect. Please reload the page." => "Informazioni sulla vCard non corrette. Ricarica la pagina.",
"Error deleting contact property." => "Errore durante l'eliminazione della proprietà del contatto.",
"Contact ID is missing." => "Manca l'ID del contatto.",
-"Missing contact id." => "ID di contatto mancante.",
"No photo path was submitted." => "Non è stato inviato alcun percorso a una foto.",
"File doesn't exist:" => "Il file non esiste:",
"Error loading image." => "Errore di caricamento immagine.",
-"element name is not set." => "il nome dell'elemento non è impostato.",
+"Error getting contact object." => "Errore di recupero dell'oggetto contatto.",
+"Error getting PHOTO property." => "Errore di recupero della proprietà FOTO.",
+"Error saving contact." => "Errore di salvataggio del contatto.",
+"Error resizing image" => "Errore di ridimensionamento dell'immagine",
+"Error cropping image" => "Errore di ritaglio dell'immagine",
+"Error creating temporary image" => "Errore durante la creazione dell'immagine temporanea",
+"Error finding image: " => "Errore durante la ricerca dell'immagine: ",
"checksum is not set." => "il codice di controllo non è impostato.",
"Information about vCard is incorrect. Please reload the page: " => "Le informazioni della vCard non sono corrette. Ricarica la pagina: ",
"Something went FUBAR. " => "Qualcosa è andato storto. ",
@@ -41,8 +45,27 @@
"The uploaded file was only partially uploaded" => "Il file è stato inviato solo parzialmente",
"No file was uploaded" => "Nessun file è stato inviato",
"Missing a temporary folder" => "Manca una cartella temporanea",
+"Couldn't save temporary image: " => "Impossibile salvare l'immagine temporanea: ",
+"Couldn't load temporary image: " => "Impossibile caricare l'immagine temporanea: ",
+"No file was uploaded. Unknown error" => "Nessun file è stato inviato. Errore sconosciuto",
"Contacts" => "Contatti",
-"Drop a VCF file to import contacts." => "Rilascia un file VCF per importare i contatti.",
+"Sorry, this functionality has not been implemented yet" => "Siamo spiacenti, questa funzionalità non è stata ancora implementata",
+"Not implemented" => "Non implementata",
+"Couldn't get a valid address." => "Impossibile ottenere un indirizzo valido.",
+"Error" => "Errore",
+"Contact" => "Contatto",
+"New" => "Nuovo",
+"New Contact" => "Nuovo contatto",
+"This property has to be non-empty." => "Questa proprietà non può essere vuota.",
+"Couldn't serialize elements." => "Impossibile serializzare gli elementi.",
+"'deleteProperty' called without type argument. Please report at bugs.owncloud.org" => "'deleteProperty' invocata senza l'argomento di tipo. Segnalalo a bugs.owncloud.org",
+"Edit name" => "Modifica il nome",
+"No files selected for upload." => "Nessun file selezionato per l'invio",
+"The file you are trying to upload exceed the maximum size for file uploads on this server." => "Il file che stai cercando di inviare supera la dimensione massima per l'invio dei file su questo server.",
+"Select type" => "Seleziona il tipo",
+"Result: " => "Risultato: ",
+" imported, " => " importato, ",
+" failed." => " non riuscito.",
"Addressbook not found." => "Rubrica non trovata.",
"This is not your addressbook." => "Questa non è la tua rubrica.",
"Contact could not be found." => "Il contatto non può essere trovato.",
@@ -60,25 +83,54 @@
"Video" => "Video",
"Pager" => "Cercapersone",
"Internet" => "Internet",
+"Birthday" => "Compleanno",
+"Business" => "Lavoro",
+"Call" => "Chiama",
+"Clients" => "Client",
+"Deliverer" => "Corriere",
+"Holidays" => "Festività",
+"Ideas" => "Idee",
+"Journey" => "Viaggio",
+"Jubilee" => "Anniversario",
+"Meeting" => "Riunione",
+"Other" => "Altro",
+"Personal" => "Personale",
+"Projects" => "Progetti",
+"Questions" => "Domande",
"{name}'s Birthday" => "Data di nascita di {name}",
-"Contact" => "Contatto",
"Add Contact" => "Aggiungi contatto",
+"Import" => "Importa",
"Addressbooks" => "Rubriche",
+"Close" => "Chiudi",
+"Keyboard shortcuts" => "Scorciatoie da tastiera",
+"Navigation" => "Navigazione",
+"Next contact in list" => "Contatto successivo in elenco",
+"Previous contact in list" => "Contatto precedente in elenco",
+"Expand/collapse current addressbook" => "Espandi/Contrai la rubrica corrente",
+"Next/previous addressbook" => "Rubrica successiva/precedente",
+"Actions" => "Azioni",
+"Refresh contacts list" => "Aggiorna l'elenco dei contatti",
+"Add new contact" => "Aggiungi un nuovo contatto",
+"Add new addressbook" => "Aggiungi una nuova rubrica",
+"Delete current contact" => "Elimina il contatto corrente",
"Configure Address Books" => "Configura rubrica",
"New Address Book" => "Nuova rubrica",
-"Import from VCF" => "Importa da VCF",
"CardDav Link" => "Link CardDav",
"Download" => "Scarica",
"Edit" => "Modifica",
"Delete" => "Elimina",
-"Download contact" => "Scarica contatto",
-"Delete contact" => "Elimina contatto",
"Drop photo to upload" => "Rilascia una foto da inviare",
+"Delete current photo" => "Elimina la foto corrente",
+"Edit current photo" => "Modifica la foto corrente",
+"Upload new photo" => "Invia una nuova foto",
+"Select photo from ownCloud" => "Seleziona la foto da ownCloud",
"Format custom, Short name, Full name, Reverse or Reverse with comma" => "Formato personalizzato, nome breve, nome completo, invertito o invertito con virgola",
"Edit name details" => "Modifica dettagli del nome",
"Nickname" => "Pseudonimo",
"Enter nickname" => "Inserisci pseudonimo",
-"Birthday" => "Compleanno",
+"Web site" => "Sito web",
+"http://www.somesite.com" => "http://www.somesite.com",
+"Go to web site" => "Vai al sito web",
"dd-mm-yyyy" => "gg-mm-aaaa",
"Groups" => "Gruppi",
"Separate groups with commas" => "Separa i gruppi con virgole",
@@ -94,24 +146,24 @@
"Edit address details" => "Modifica dettagli dell'indirizzo",
"Add notes here." => "Aggiungi qui le note.",
"Add field" => "Aggiungi campo",
-"Profile picture" => "Immagine del profilo",
"Phone" => "Telefono",
"Note" => "Nota",
-"Delete current photo" => "Elimina la foto corrente",
-"Edit current photo" => "Modifica la foto corrente",
-"Upload new photo" => "Invia una nuova foto",
-"Select photo from ownCloud" => "Seleziona la foto da ownCloud",
+"Download contact" => "Scarica contatto",
+"Delete contact" => "Elimina contatto",
+"The temporary image has been removed from cache." => "L'immagine temporanea è stata rimossa dalla cache.",
"Edit address" => "Modifica indirizzo",
"Type" => "Tipo",
"PO Box" => "Casella postale",
+"Street address" => "Indirizzo",
+"Street and number" => "Via e numero",
"Extended" => "Esteso",
-"Street" => "Via",
+"Apartment number etc." => "Numero appartamento ecc.",
"City" => "Città",
"Region" => "Regione",
+"E.g. state or province" => "Ad es. stato o provincia",
"Zipcode" => "CAP",
+"Postal code" => "CAP",
"Country" => "Stato",
-"Edit categories" => "Modifica categorie",
-"Add" => "Aggiungi",
"Addressbook" => "Rubrica",
"Hon. prefixes" => "Prefissi onorifici",
"Miss" => "Sig.na",
@@ -143,15 +195,16 @@
"Please choose the addressbook" => "Scegli la rubrica",
"create a new addressbook" => "crea una nuova rubrica",
"Name of new addressbook" => "Nome della nuova rubrica",
-"Import" => "Importa",
"Importing contacts" => "Importazione contatti",
-"Select address book to import to:" => "Seleziona la rubrica di destinazione:",
-"Select from HD" => "Seleziona da disco",
"You have no contacts in your addressbook." => "Non hai contatti nella rubrica.",
"Add contact" => "Aggiungi contatto",
"Configure addressbooks" => "Configura rubriche",
+"Select Address Books" => "Seleziona rubriche",
+"Enter name" => "Inserisci il nome",
+"Enter description" => "Inserisci una descrizione",
"CardDAV syncing addresses" => "Indirizzi di sincronizzazione CardDAV",
"more info" => "altre informazioni",
"Primary address (Kontact et al)" => "Indirizzo principale (Kontact e altri)",
-"iOS/OS X" => "iOS/OS X"
+"iOS/OS X" => "iOS/OS X",
+"Read only vCard directory link(s)" => "Collegamento(i) cartella vCard sola lettura"
);
diff --git a/apps/contacts/l10n/vi.php b/apps/contacts/l10n/vi.php
new file mode 100644
index 00000000000..5713ede7b00
--- /dev/null
+++ b/apps/contacts/l10n/vi.php
@@ -0,0 +1,48 @@
+<?php $TRANSLATIONS = array(
+"element name is not set." => "tên phần tử không được thiết lập.",
+"id is not set." => "id không được thiết lập.",
+"No ID provided" => "Không có ID được cung cấp",
+"No address books found." => "Không tìm thấy sổ địa chỉ.",
+"No contacts found." => "Không tìm thấy danh sách",
+"Missing ID" => "Missing ID",
+"Error reading contact photo." => "Lỗi đọc liên lạc hình ảnh.",
+"The loading photo is not valid." => "Các hình ảnh tải không hợp lệ.",
+"File doesn't exist:" => "Tập tin không tồn tại",
+"Error loading image." => "Lỗi khi tải hình ảnh.",
+"Error uploading contacts to storage." => "Lỗi tải lên danh sách địa chỉ để lưu trữ.",
+"There is no error, the file uploaded with success" => "Không có lỗi, các tập tin tải lên thành công",
+"Contacts" => "Liên lạc",
+"Contact" => "Danh sách",
+"Address" => "Địa chỉ",
+"Telephone" => "Điện thoại bàn",
+"Email" => "Email",
+"Organization" => "Tổ chức",
+"Work" => "Công việc",
+"Home" => "Nhà",
+"Mobile" => "Di động",
+"Fax" => "Fax",
+"Video" => "Video",
+"Pager" => "số trang",
+"Birthday" => "Ngày sinh nhật",
+"Add Contact" => "Thêm liên lạc",
+"Addressbooks" => "Sổ địa chỉ",
+"CardDav Link" => "CardDav Link",
+"Download" => "Tải về",
+"Edit" => "Sửa",
+"Delete" => "Xóa",
+"Phone" => "Điện thoại",
+"Delete contact" => "Xóa liên lạc",
+"PO Box" => "Hòm thư bưu điện",
+"City" => "Thành phố",
+"Region" => "Vùng/miền",
+"Zipcode" => "Mã bưu điện",
+"Country" => "Quốc gia",
+"Addressbook" => "Sổ địa chỉ",
+"New Addressbook" => "Sổ địa chỉ mới",
+"Edit Addressbook" => "Sửa sổ địa chỉ",
+"Displayname" => "Hiển thị tên",
+"Active" => "Kích hoạt",
+"Save" => "Lưu",
+"Submit" => "Submit",
+"Cancel" => "Hủy"
+);
diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php
index 1bc4a195534..b2dde12684c 100644
--- a/apps/contacts/templates/index.php
+++ b/apps/contacts/templates/index.php
@@ -32,6 +32,38 @@
echo $this->inc('part.no_contacts');
}
?>
+ <div class="hidden" id="ninjahelp">
+ <a class="close" tabindex="0" role="button">
+ <img class="svg" src="core/img/actions/delete.svg" alt="<?php echo $l->t('Close'); ?>" />
+ </a>
+ <h2><?php echo $l->t('Keyboard shortcuts'); ?></h2>
+ <div class="help-section">
+ <h3><?php echo $l->t('Navigation'); ?></h3>
+ <dl>
+ <dt>j/Down/Space</dt>
+ <dd><?php echo $l->t('Next contact in list'); ?></dd>
+ <dt>k/Up/Shift-Space</dt>
+ <dd><?php echo $l->t('Previous contact in list'); ?></dd>
+ <dt>o/Enter</dt>
+ <dd><?php echo $l->t('Expand/collapse current addressbook'); ?></dd>
+ <dt>n/p</dt>
+ <dd><?php echo $l->t('Next/previous addressbook'); ?></dd>
+ </dl>
+ </div>
+ <div class="help-section">
+ <h3><?php echo $l->t('Actions'); ?></h3>
+ <dl>
+ <dt>r</dt>
+ <dd><?php echo $l->t('Refresh contacts list'); ?></dd>
+ <dt>a</dt>
+ <dd><?php echo $l->t('Add new contact'); ?></dd>
+ <dt>Shift-a</dt>
+ <dd><?php echo $l->t('Add new addressbook'); ?></dd>
+ <dt>Shift-Delete</dt>
+ <dd><?php echo $l->t('Delete current contact'); ?></dd>
+ </dl>
+ </div>
+ </div>
</div>
<!-- Dialogs -->
<div id="dialog_holder"></div>
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
index 7236deb65c9..cc9208ad08f 100644
--- a/apps/files/ajax/newfile.php
+++ b/apps/files/ajax/newfile.php
@@ -1,16 +1,25 @@
<?php
// Init owncloud
+global $eventSource;
+if(!OC_User::isLoggedIn()){
+ exit;
+}
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
+session_write_close();
// Get the params
-$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : '';
-$filename = isset( $_POST['filename'] ) ? stripslashes($_POST['filename']) : '';
-$content = isset( $_POST['content'] ) ? $_POST['content'] : '';
-$source = isset( $_POST['source'] ) ? stripslashes($_POST['source']) : '';
+$dir = isset( $_REQUEST['dir'] ) ? stripslashes($_REQUEST['dir']) : '';
+$filename = isset( $_REQUEST['filename'] ) ? stripslashes($_REQUEST['filename']) : '';
+$content = isset( $_REQUEST['content'] ) ? $_REQUEST['content'] : '';
+$source = isset( $_REQUEST['source'] ) ? stripslashes($_REQUEST['source']) : '';
+
+if($source){
+ $eventSource=new OC_EventSource();
+}else{
+ OC_JSON::callCheck();
+}
if($filename == '') {
OCP\JSON::error(array("data" => array( "message" => "Empty Filename" )));
@@ -21,22 +30,49 @@ if(strpos($filename,'/')!==false){
exit();
}
+function progress($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max){
+ static $filesize = 0;
+ static $lastsize = 0;
+ global $eventSource;
+
+ switch($notification_code) {
+ case STREAM_NOTIFY_FILE_SIZE_IS:
+ $filesize = $bytes_max;
+ break;
+
+ case STREAM_NOTIFY_PROGRESS:
+ if ($bytes_transferred > 0) {
+ if (!isset($filesize)) {
+ } else {
+ $progress = (int)(($bytes_transferred/$filesize)*100);
+ if($progress>$lastsize){//limit the number or messages send
+ $eventSource->send('progress',$progress);
+ }
+ $lastsize=$progress;
+ }
+ }
+ break;
+ }
+}
+
if($source){
if(substr($source,0,8)!='https://' and substr($source,0,7)!='http://'){
OCP\JSON::error(array("data" => array( "message" => "Not a valid source" )));
exit();
}
- $sourceStream=fopen($source,'rb');
+
+ $ctx = stream_context_create(null, array('notification' =>'progress'));
+ $sourceStream=fopen($source,'rb', false, $ctx);
$target=$dir.'/'.$filename;
$result=OC_Filesystem::file_put_contents($target,$sourceStream);
if($result){
$mime=OC_Filesystem::getMimetype($target);
- OCP\JSON::success(array("data" => array('mime'=>$mime)));
- exit();
+ $eventSource->send('success',$mime);
}else{
- OCP\JSON::error(array("data" => array( "message" => "Error while downloading ".$source. ' to '.$target )));
- exit();
+ $eventSource->send('error',"Error while downloading ".$source. ' to '.$target);
}
+ $eventSource->close();
+ exit();
}else{
if($content){
if(OC_Filesystem::file_put_contents($dir.'/'.$filename,$content)){
diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php
index 6fcf97688c2..eef38858516 100644
--- a/apps/files/ajax/scan.php
+++ b/apps/files/ajax/scan.php
@@ -16,6 +16,11 @@ session_write_close();
if($force or !OC_FileCache::inCache('')){
if(!$checkOnly){
OCP\DB::beginTransaction();
+
+ if(OC_Cache::isFast()){
+ OC_Cache::clear('fileid/'); //make sure the old fileid's don't mess things up
+ }
+
OC_FileCache::scan($dir,$eventSource);
OC_FileCache::clean();
OCP\DB::commit();
diff --git a/apps/files/appinfo/update.php b/apps/files/appinfo/update.php
index f9953ba4de5..5514aed197f 100644
--- a/apps/files/appinfo/update.php
+++ b/apps/files/appinfo/update.php
@@ -1,5 +1,16 @@
<?php
+// fix webdav properties, remove namespace information between curly bracket (update from OC4 to OC5)
+$installedVersion=OCP\Config::getAppValue('files', 'installed_version');
+if (version_compare($installedVersion, '1.1.4', '<')) {
+ $query = OC_DB::prepare( "SELECT propertyname, propertypath, userid FROM `*PREFIX*properties`" );
+ $result = $query->execute();
+ while( $row = $result->fetchRow()){
+ $query = OC_DB::prepare( 'UPDATE *PREFIX*properties SET propertyname = ? WHERE userid = ? AND propertypath = ?' );
+ $query->execute( array( preg_replace("/^{.*}/", "", $row["propertyname"]),$row["userid"], $row["propertypath"] ));
+ }
+}
+
//update from OC 3
//try to remove remaining files.
diff --git a/apps/files/appinfo/version b/apps/files/appinfo/version
index 9c1218c201f..1b87bcd0b09 100644
--- a/apps/files/appinfo/version
+++ b/apps/files/appinfo/version
@@ -1 +1 @@
-1.1.3 \ No newline at end of file
+1.1.4 \ No newline at end of file
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 86c5185bf72..a4e2361feeb 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -497,23 +497,27 @@ $(document).ready(function() {
localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
}
localName = getUniqueName(localName);
- $.post(
- OC.filePath('files','ajax','newfile.php'),
- {dir:$('#dir').val(),source:name,filename:localName},
- function(result){
- if(result.status == 'success'){
- var date=new Date();
- FileList.addFile(localName,0,date);
- var tr=$('tr').filterAttr('data-file',localName);
- tr.data('mime',result.data.mime);
- getMimeIcon(result.data.mime,function(path){
- tr.find('td.filename').attr('style','background-image:url('+path+')');
- });
- }else{
+ $('#uploadprogressbar').progressbar({value:0});
+ $('#uploadprogressbar').fadeIn();
- }
- }
- );
+ var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
+ eventSource.listen('progress',function(progress){
+ $('#uploadprogressbar').progressbar('value',progress);
+ });
+ eventSource.listen('success',function(mime){
+ $('#uploadprogressbar').fadeOut();
+ var date=new Date();
+ FileList.addFile(localName,0,date);
+ var tr=$('tr').filterAttr('data-file',localName);
+ tr.data('mime',mime);
+ getMimeIcon(mime,function(path){
+ tr.find('td.filename').attr('style','background-image:url('+path+')');
+ });
+ });
+ eventSource.listen('error',function(error){
+ $('#uploadprogressbar').fadeOut();
+ alert(error);
+ });
break;
}
var li=$(this).parent();
diff --git a/apps/files/l10n/es.php b/apps/files/l10n/es.php
index 67bfb4702e8..506218815bb 100644
--- a/apps/files/l10n/es.php
+++ b/apps/files/l10n/es.php
@@ -7,8 +7,21 @@
"Missing a temporary folder" => "Falta un directorio temporal",
"Failed to write to disk" => "La escritura en disco ha fallado",
"Files" => "Archivos",
+"Unshare" => "No compartir",
+"Delete" => "Eliminado",
+"undo deletion" => "deshacer la eliminación",
+"generating ZIP-file, it may take some time." => "generando un fichero ZIP, puede llevar un tiempo.",
+"Unable to upload your file as it is a directory or has 0 bytes" => "No ha sido posible subir tu archivo porque es un directorio o tiene 0 bytes",
+"Upload Error" => "Error al subir el archivo",
+"Pending" => "Pendiente",
+"Upload cancelled." => "Subida cancelada.",
+"Invalid name, '/' is not allowed." => "Nombre no válido, '/' no está permitido.",
"Size" => "Tamaño",
"Modified" => "Modificado",
+"folder" => "carpeta",
+"folders" => "carpetas",
+"file" => "archivo",
+"files" => "archivos",
"File handling" => "Tratamiento de archivos",
"Maximum upload size" => "Tamaño máximo de subida",
"max. possible: " => "máx. posible:",
@@ -26,7 +39,6 @@
"Name" => "Nombre",
"Share" => "Compartir",
"Download" => "Descargar",
-"Delete" => "Eliminado",
"Upload too large" => "El archivo es demasiado grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Los archivos que estás intentando subir sobrepasan el tamaño máximo permitido por este servidor.",
"Files are being scanned, please wait." => "Se están escaneando los archivos, por favor espere.",
diff --git a/apps/files/l10n/it.php b/apps/files/l10n/it.php
index 82871826c18..0bf113eba1b 100644
--- a/apps/files/l10n/it.php
+++ b/apps/files/l10n/it.php
@@ -7,8 +7,21 @@
"Missing a temporary folder" => "Cartella temporanea mancante",
"Failed to write to disk" => "Scrittura su disco non riuscita",
"Files" => "File",
+"Unshare" => "Rimuovi condivisione",
+"Delete" => "Elimina",
+"undo deletion" => "annulla l'eliminazione",
+"generating ZIP-file, it may take some time." => "creazione file ZIP, potrebbe richiedere del tempo.",
+"Unable to upload your file as it is a directory or has 0 bytes" => "Impossibile inviare il file poiché è una cartella o ha dimensione 0 byte",
+"Upload Error" => "Errore di invio",
+"Pending" => "In corso",
+"Upload cancelled." => "Invio annullato",
+"Invalid name, '/' is not allowed." => "Nome non valido",
"Size" => "Dimensione",
"Modified" => "Modificato",
+"folder" => "cartella",
+"folders" => "cartelle",
+"file" => "file",
+"files" => "file",
"File handling" => "Gestione file",
"Maximum upload size" => "Dimensione massima upload",
"max. possible: " => "numero mass.: ",
@@ -26,7 +39,6 @@
"Name" => "Nome",
"Share" => "Condividi",
"Download" => "Scarica",
-"Delete" => "Elimina",
"Upload too large" => "Il file caricato è troppo grande",
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "I file che stai provando a caricare superano la dimensione massima consentita su questo server.",
"Files are being scanned, please wait." => "Scansione dei file in corso, attendi",
diff --git a/apps/files/l10n/vi.php b/apps/files/l10n/vi.php
new file mode 100644
index 00000000000..c2284d5feb9
--- /dev/null
+++ b/apps/files/l10n/vi.php
@@ -0,0 +1,31 @@
+<?php $TRANSLATIONS = array(
+"Files" => "Tập tin",
+"Delete" => "Xóa",
+"Upload Error" => "Tải lên lỗi",
+"Pending" => "Chờ",
+"Upload cancelled." => "Hủy tải lên",
+"Invalid name, '/' is not allowed." => "Tên không hợp lệ ,không được phép dùng '/'",
+"Size" => "Kích cỡ",
+"Modified" => "Thay đổi",
+"folder" => "folder",
+"folders" => "folders",
+"file" => "file",
+"files" => "files",
+"File handling" => "Xử lý tập tin",
+"Maximum upload size" => "Kích thước tối đa ",
+"Enable ZIP-download" => "Cho phép ZIP-download",
+"0 is unlimited" => "0 là không giới hạn",
+"Maximum input size for ZIP files" => "Kích thước tối đa cho các tập tin ZIP",
+"New" => "Mới",
+"Text file" => "Tập tin văn bản",
+"Folder" => "Folder",
+"From url" => "Từ url",
+"Upload" => "Tải lên",
+"Cancel upload" => "Hủy upload",
+"Nothing in here. Upload something!" => "Không có gì ở đây .Hãy tải lên một cái gì đó !",
+"Name" => "Tên",
+"Share" => "Chia sẻ",
+"Download" => "Tải xuống",
+"Upload too large" => "File tải lên quá lớn",
+"Files are being scanned, please wait." => "Tập tin đang được quét ,vui lòng chờ."
+);
diff --git a/apps/files_imageviewer/js/jquery.fancybox-1.3.4.js b/apps/files_imageviewer/js/jquery.fancybox-1.3.4.js
index a1db7b6198c..e5493cd9393 100644
--- a/apps/files_imageviewer/js/jquery.fancybox-1.3.4.js
+++ b/apps/files_imageviewer/js/jquery.fancybox-1.3.4.js
@@ -124,9 +124,7 @@
} else if (href.indexOf("#") === 0) {
type = 'inline';
- } else {
- type = 'ajax';
- }
+ }
}
if (!type) {
diff --git a/apps/files_imageviewer/js/jquery.fancybox-1.3.4.pack.js b/apps/files_imageviewer/js/jquery.fancybox-1.3.4.pack.js
index e5ee2ae3595..260f2c2d466 100644
--- a/apps/files_imageviewer/js/jquery.fancybox-1.3.4.pack.js
+++ b/apps/files_imageviewer/js/jquery.fancybox-1.3.4.pack.js
@@ -1 +1 @@
-(function(B){var L,T,Q,M,d,m,J,A,O,z,C=0,H={},j=[],e=0,G={},y=[],f=null,o=new Image(),i=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,k=/[^\.]\.(swf)\s*$/i,p,N=1,h=0,t="",b,c,P=false,s=B.extend(B("<div/>")[0],{prop:0}),S=B.browser.msie&&B.browser.version<7&&!window.XMLHttpRequest,r=function(){T.hide();o.onerror=o.onload=null;if(f){f.abort()}L.empty()},x=function(){if(false===H.onError(j,C,H)){T.hide();P=false;return}H.titleShow=false;H.width="auto";H.height="auto";L.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');n()},w=function(){var Z=j[C],W,Y,ab,aa,V,X;r();H=B.extend({},B.fn.fancybox.defaults,(typeof B(Z).data("fancybox")=="undefined"?H:B(Z).data("fancybox")));X=H.onStart(j,C,H);if(X===false){P=false;return}else{if(typeof X=="object"){H=B.extend(H,X)}}ab=H.title||(Z.nodeName?B(Z).attr("title"):Z.title)||"";if(Z.nodeName&&!H.orig){H.orig=B(Z).children("img:first").length?B(Z).children("img:first"):B(Z)}if(ab===""&&H.orig&&H.titleFromAlt){ab=H.orig.attr("alt")}ab=ab.replace(/</,"&lt;").replace(/>/,"&gt;");W=H.href||(Z.nodeName?B(Z).attr("href"):Z.href)||null;if((/^(?:javascript)/i).test(W)||W=="#"){W=null}if(H.type){Y=H.type;if(!W){W=H.content}}else{if(H.content){Y="html"}else{if(W){if(W.match(i)){Y="image"}else{if(W.match(k)){Y="swf"}else{if(B(Z).hasClass("iframe")){Y="iframe"}else{if(W.indexOf("#")===0){Y="inline"}else{Y="ajax"}}}}}}}if(!Y){x();return}if(Y=="inline"){Z=W.substr(W.indexOf("#"));Y=B(Z).length>0?"inline":"ajax"}H.type=Y;H.href=W;H.title=ab;if(H.autoDimensions){if(H.type=="html"||H.type=="inline"||H.type=="ajax"){H.width="auto";H.height="auto"}else{H.autoDimensions=false}}if(H.modal){H.overlayShow=true;H.hideOnOverlayClick=false;H.hideOnContentClick=false;H.enableEscapeButton=false;H.showCloseButton=false}H.padding=parseInt(H.padding,10);H.margin=parseInt(H.margin,10);L.css("padding",(H.padding+H.margin));B(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){B(this).replaceWith(m.children())});switch(Y){case"html":L.html(H.content);n();break;case"inline":if(B(Z).parent().is("#fancybox-content")===true){P=false;return}B('<div class="fancybox-inline-tmp" />').hide().insertBefore(B(Z)).bind("fancybox-cleanup",function(){B(this).replaceWith(m.children())}).bind("fancybox-cancel",function(){B(this).replaceWith(L.children())});B(Z).appendTo(L);n();break;case"image":P=false;B.fancybox.showActivity();o=new Image();o.onerror=function(){x()};o.onload=function(){P=true;o.onerror=o.onload=null;F()};o.src=W;break;case"swf":H.scrolling="no";aa='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+H.width+'" height="'+H.height+'"><param name="movie" value="'+W+'"></param>';V="";B.each(H.swf,function(ac,ad){aa+='<param name="'+ac+'" value="'+ad+'"></param>';V+=" "+ac+'="'+ad+'"'});aa+='<embed src="'+W+'" type="application/x-shockwave-flash" width="'+H.width+'" height="'+H.height+'"'+V+"></embed></object>";L.html(aa);n();break;case"ajax":P=false;B.fancybox.showActivity();H.ajax.win=H.ajax.success;f=B.ajax(B.extend({},H.ajax,{url:W,data:H.ajax.data||{},error:function(ac,ae,ad){if(ac.status>0){x()}},success:function(ad,af,ac){var ae=typeof ac=="object"?ac:f;if(ae.status==200){if(typeof H.ajax.win=="function"){X=H.ajax.win(W,ad,af,ac);if(X===false){T.hide();return}else{if(typeof X=="string"||typeof X=="object"){ad=X}}}L.html(ad);n()}}}));break;case"iframe":E();break}},n=function(){var V=H.width,W=H.height;if(V.toString().indexOf("%")>-1){V=parseInt((B(window).width()-(H.margin*2))*parseFloat(V)/100,10)+"px"}else{V=V=="auto"?"auto":V+"px"}if(W.toString().indexOf("%")>-1){W=parseInt((B(window).height()-(H.margin*2))*parseFloat(W)/100,10)+"px"}else{W=W=="auto"?"auto":W+"px"}L.wrapInner('<div style="width:'+V+";height:"+W+";overflow: "+(H.scrolling=="auto"?"auto":(H.scrolling=="yes"?"scroll":"hidden"))+';position:relative;"></div>');H.width=L.width();H.height=L.height();E()},F=function(){H.width=o.width;H.height=o.height;B("<img />").attr({id:"fancybox-img",src:o.src,alt:H.title}).appendTo(L);E()},E=function(){var W,V;T.hide();if(M.is(":visible")&&false===G.onCleanup(y,e,G)){B.event.trigger("fancybox-cancel");P=false;return}P=true;B(m.add(Q)).unbind();B(window).unbind("resize.fb scroll.fb");B(document).unbind("keydown.fb");if(M.is(":visible")&&G.titlePosition!=="outside"){M.css("height",M.height())}y=j;e=C;G=H;if(G.overlayShow){Q.css({"background-color":G.overlayColor,opacity:G.overlayOpacity,cursor:G.hideOnOverlayClick?"pointer":"auto",height:B(document).height()});if(!Q.is(":visible")){if(S){B("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"})}Q.show()}}else{Q.hide()}c=R();l();if(M.is(":visible")){B(J.add(O).add(z)).hide();W=M.position(),b={top:W.top,left:W.left,width:M.width(),height:M.height()};V=(b.width==c.width&&b.height==c.height);m.fadeTo(G.changeFade,0.3,function(){var X=function(){m.html(L.contents()).fadeTo(G.changeFade,1,v)};B.event.trigger("fancybox-change");m.empty().removeAttr("filter").css({"border-width":G.padding,width:c.width-G.padding*2,height:H.autoDimensions?"auto":c.height-h-G.padding*2});if(V){X()}else{s.prop=0;B(s).animate({prop:1},{duration:G.changeSpeed,easing:G.easingChange,step:U,complete:X})}});return}M.removeAttr("style");m.css("border-width",G.padding);if(G.transitionIn=="elastic"){b=I();m.html(L.contents());M.show();if(G.opacity){c.opacity=0}s.prop=0;B(s).animate({prop:1},{duration:G.speedIn,easing:G.easingIn,step:U,complete:v});return}if(G.titlePosition=="inside"&&h>0){A.show()}m.css({width:c.width-G.padding*2,height:H.autoDimensions?"auto":c.height-h-G.padding*2}).html(L.contents());M.css(c).fadeIn(G.transitionIn=="none"?0:G.speedIn,v)},D=function(V){if(V&&V.length){if(G.titlePosition=="float"){return'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+V+'</td><td id="fancybox-title-float-right"></td></tr></table>'}return'<div id="fancybox-title-'+G.titlePosition+'">'+V+"</div>"}return false},l=function(){t=G.title||"";h=0;A.empty().removeAttr("style").removeClass();if(G.titleShow===false){A.hide();return}t=B.isFunction(G.titleFormat)?G.titleFormat(t,y,e,G):D(t);if(!t||t===""){A.hide();return}A.addClass("fancybox-title-"+G.titlePosition).html(t).appendTo("body").show();switch(G.titlePosition){case"inside":A.css({width:c.width-(G.padding*2),marginLeft:G.padding,marginRight:G.padding});h=A.outerHeight(true);A.appendTo(d);c.height+=h;break;case"over":A.css({marginLeft:G.padding,width:c.width-(G.padding*2),bottom:G.padding}).appendTo(d);break;case"float":A.css("left",parseInt((A.width()-c.width-40)/2,10)*-1).appendTo(M);break;default:A.css({width:c.width-(G.padding*2),paddingLeft:G.padding,paddingRight:G.padding}).appendTo(M);break}A.hide()},g=function(){if(G.enableEscapeButton||G.enableKeyboardNav){B(document).bind("keydown.fb",function(V){if(V.keyCode==27&&G.enableEscapeButton){V.preventDefault();B.fancybox.close()}else{if((V.keyCode==37||V.keyCode==39)&&G.enableKeyboardNav&&V.target.tagName!=="INPUT"&&V.target.tagName!=="TEXTAREA"&&V.target.tagName!=="SELECT"){V.preventDefault();B.fancybox[V.keyCode==37?"prev":"next"]()}}})}if(!G.showNavArrows){O.hide();z.hide();return}if((G.cyclic&&y.length>1)||e!==0){O.show()}if((G.cyclic&&y.length>1)||e!=(y.length-1)){z.show()}},v=function(){if(!B.support.opacity){m.get(0).style.removeAttribute("filter");M.get(0).style.removeAttribute("filter")}if(H.autoDimensions){m.css("height","auto")}M.css("height","auto");if(t&&t.length){A.show()}if(G.showCloseButton){J.show()}g();if(G.hideOnContentClick){m.bind("click",B.fancybox.close)}if(G.hideOnOverlayClick){Q.bind("click",B.fancybox.close)}B(window).bind("resize.fb",B.fancybox.resize);if(G.centerOnScroll){B(window).bind("scroll.fb",B.fancybox.center)}if(G.type=="iframe"){B('<iframe id="fancybox-frame" name="fancybox-frame'+new Date().getTime()+'" frameborder="0" hspace="0" '+(B.browser.msie?'allowtransparency="true""':"")+' scrolling="'+H.scrolling+'" src="'+G.href+'"></iframe>').appendTo(m)}M.show();P=false;B.fancybox.center();G.onComplete(y,e,G);K()},K=function(){var V,W;if((y.length-1)>e){V=y[e+1].href;if(typeof V!=="undefined"&&V.match(i)){W=new Image();W.src=V}}if(e>0){V=y[e-1].href;if(typeof V!=="undefined"&&V.match(i)){W=new Image();W.src=V}}},U=function(W){var V={width:parseInt(b.width+(c.width-b.width)*W,10),height:parseInt(b.height+(c.height-b.height)*W,10),top:parseInt(b.top+(c.top-b.top)*W,10),left:parseInt(b.left+(c.left-b.left)*W,10)};if(typeof c.opacity!=="undefined"){V.opacity=W<0.5?0.5:W}M.css(V);m.css({width:V.width-G.padding*2,height:V.height-(h*W)-G.padding*2})},u=function(){return[B(window).width()-(G.margin*2),B(window).height()-(G.margin*2),B(document).scrollLeft()+G.margin,B(document).scrollTop()+G.margin]},R=function(){var V=u(),Z={},W=G.autoScale,X=G.padding*2,Y;if(G.width.toString().indexOf("%")>-1){Z.width=parseInt((V[0]*parseFloat(G.width))/100,10)}else{Z.width=G.width+X}if(G.height.toString().indexOf("%")>-1){Z.height=parseInt((V[1]*parseFloat(G.height))/100,10)}else{Z.height=G.height+X}if(W&&(Z.width>V[0]||Z.height>V[1])){if(H.type=="image"||H.type=="swf"){Y=(G.width)/(G.height);if((Z.width)>V[0]){Z.width=V[0];Z.height=parseInt(((Z.width-X)/Y)+X,10)}if((Z.height)>V[1]){Z.height=V[1];Z.width=parseInt(((Z.height-X)*Y)+X,10)}}else{Z.width=Math.min(Z.width,V[0]);Z.height=Math.min(Z.height,V[1])}}Z.top=parseInt(Math.max(V[3]-20,V[3]+((V[1]-Z.height-40)*0.5)),10);Z.left=parseInt(Math.max(V[2]-20,V[2]+((V[0]-Z.width-40)*0.5)),10);return Z},q=function(V){var W=V.offset();W.top+=parseInt(V.css("paddingTop"),10)||0;W.left+=parseInt(V.css("paddingLeft"),10)||0;W.top+=parseInt(V.css("border-top-width"),10)||0;W.left+=parseInt(V.css("border-left-width"),10)||0;W.width=V.width();W.height=V.height();return W},I=function(){var Y=H.orig?B(H.orig):false,X={},W,V;if(Y&&Y.length){W=q(Y);X={width:W.width+(G.padding*2),height:W.height+(G.padding*2),top:W.top-G.padding-20,left:W.left-G.padding-20}}else{V=u();X={width:G.padding*2,height:G.padding*2,top:parseInt(V[3]+V[1]*0.5,10),left:parseInt(V[2]+V[0]*0.5,10)}}return X},a=function(){if(!T.is(":visible")){clearInterval(p);return}B("div",T).css("top",(N*-40)+"px");N=(N+1)%12};B.fn.fancybox=function(V){if(!B(this).length){return this}B(this).data("fancybox",B.extend({},V,(B.metadata?B(this).metadata():{}))).unbind("click.fb").bind("click.fb",function(X){X.preventDefault();if(P){return}P=true;B(this).blur();j=[];C=0;var W=B(this).attr("rel")||"";if(!W||W==""||W==="nofollow"){j.push(this)}else{j=B("a[rel="+W+"], area[rel="+W+"]");C=j.index(this)}w();return});return this};B.fancybox=function(Y){var X;if(P){return}P=true;X=typeof arguments[1]!=="undefined"?arguments[1]:{};j=[];C=parseInt(X.index,10)||0;if(B.isArray(Y)){for(var W=0,V=Y.length;W<V;W++){if(typeof Y[W]=="object"){B(Y[W]).data("fancybox",B.extend({},X,Y[W]))}else{Y[W]=B({}).data("fancybox",B.extend({content:Y[W]},X))}}j=jQuery.merge(j,Y)}else{if(typeof Y=="object"){B(Y).data("fancybox",B.extend({},X,Y))}else{Y=B({}).data("fancybox",B.extend({content:Y},X))}j.push(Y)}if(C>j.length||C<0){C=0}w()};B.fancybox.showActivity=function(){clearInterval(p);T.show();p=setInterval(a,66)};B.fancybox.hideActivity=function(){T.hide()};B.fancybox.next=function(){return B.fancybox.pos(e+1)};B.fancybox.prev=function(){return B.fancybox.pos(e-1)};B.fancybox.pos=function(V){if(P){return}V=parseInt(V);j=y;if(V>-1&&V<y.length){C=V;w()}else{if(G.cyclic&&y.length>1){C=V>=y.length?0:y.length-1;w()}}return};B.fancybox.cancel=function(){if(P){return}P=true;B.event.trigger("fancybox-cancel");r();H.onCancel(j,C,H);P=false};B.fancybox.close=function(){if(P||M.is(":hidden")){return}P=true;if(G&&false===G.onCleanup(y,e,G)){P=false;return}r();B(J.add(O).add(z)).hide();B(m.add(Q)).unbind();B(window).unbind("resize.fb scroll.fb");B(document).unbind("keydown.fb");m.find("iframe").attr("src",S&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");if(G.titlePosition!=="inside"){A.empty()}M.stop();function V(){Q.fadeOut("fast");A.empty().hide();M.hide();B.event.trigger("fancybox-cleanup");m.empty();G.onClosed(y,e,G);y=H=[];e=C=0;G=H={};P=false}if(G.transitionOut=="elastic"){b=I();var W=M.position();c={top:W.top,left:W.left,width:M.width(),height:M.height()};if(G.opacity){c.opacity=1}A.empty().hide();s.prop=1;B(s).animate({prop:0},{duration:G.speedOut,easing:G.easingOut,step:U,complete:V})}else{M.fadeOut(G.transitionOut=="none"?0:G.speedOut,V)}};B.fancybox.resize=function(){if(Q.is(":visible")){Q.css("height",B(document).height())}B.fancybox.center(true)};B.fancybox.center=function(){var V,W;if(P){return}W=arguments[0]===true?1:0;V=u();if(!W&&(M.width()>V[0]||M.height()>V[1])){return}M.stop().animate({top:parseInt(Math.max(V[3]-20,V[3]+((V[1]-m.height()-40)*0.5)-G.padding)),left:parseInt(Math.max(V[2]-20,V[2]+((V[0]-m.width()-40)*0.5)-G.padding))},typeof arguments[0]=="number"?arguments[0]:200)};B.fancybox.init=function(){if(B("#fancybox-wrap").length){return}B("body").append(L=B('<div id="fancybox-tmp"></div>'),T=B('<div id="fancybox-loading"><div></div></div>'),Q=B('<div id="fancybox-overlay"></div>'),M=B('<div id="fancybox-wrap"></div>'));d=B('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(M);d.append(m=B('<div id="fancybox-content"></div>'),J=B('<a id="fancybox-close"></a>'),A=B('<div id="fancybox-title"></div>'),O=B('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),z=B('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));J.click(B.fancybox.close);T.click(B.fancybox.cancel);O.click(function(V){V.preventDefault();B.fancybox.prev()});z.click(function(V){V.preventDefault();B.fancybox.next()});if(B.fn.mousewheel){M.bind("mousewheel.fb",function(V,W){if(P){V.preventDefault()}else{if(B(V.target).get(0).clientHeight==0||B(V.target).get(0).scrollHeight===B(V.target).get(0).clientHeight){V.preventDefault();B.fancybox[W>0?"prev":"next"]()}}})}if(!B.support.opacity){M.addClass("fancybox-ie")}if(S){T.addClass("fancybox-ie6");M.addClass("fancybox-ie6");B('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(d)}};B.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};B(document).ready(function(){B.fancybox.init()})})(jQuery); \ No newline at end of file
+(function(B){var L,T,Q,M,d,m,J,A,O,z,C=0,H={},j=[],e=0,G={},y=[],f=null,o=new Image(),i=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,k=/[^\.]\.(swf)\s*$/i,p,N=1,h=0,t="",b,c,P=false,s=B.extend(B("<div/>")[0],{prop:0}),S=B.browser.msie&&B.browser.version<7&&!window.XMLHttpRequest,r=function(){T.hide();o.onerror=o.onload=null;if(f){f.abort()}L.empty()},x=function(){if(false===H.onError(j,C,H)){T.hide();P=false;return}H.titleShow=false;H.width="auto";H.height="auto";L.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');n()},w=function(){var Z=j[C],W,Y,ab,aa,V,X;r();H=B.extend({},B.fn.fancybox.defaults,(typeof B(Z).data("fancybox")=="undefined"?H:B(Z).data("fancybox")));X=H.onStart(j,C,H);if(X===false){P=false;return}else{if(typeof X=="object"){H=B.extend(H,X)}}ab=H.title||(Z.nodeName?B(Z).attr("title"):Z.title)||"";if(Z.nodeName&&!H.orig){H.orig=B(Z).children("img:first").length?B(Z).children("img:first"):B(Z)}if(ab===""&&H.orig&&H.titleFromAlt){ab=H.orig.attr("alt")}ab=ab.replace(/</,"&lt;").replace(/>/,"&gt;");W=H.href||(Z.nodeName?B(Z).attr("href"):Z.href)||null;if((/^(?:javascript)/i).test(W)||W=="#"){W=null}if(H.type){Y=H.type;if(!W){W=H.content}}else{if(H.content){Y="html"}else{if(W){if(W.match(i)){Y="image"}else{if(W.match(k)){Y="swf"}else{if(B(Z).hasClass("iframe")){Y="iframe"}else{if(W.indexOf("#")===0){Y="inline"}}}}}}}if(!Y){x();return}if(Y=="inline"){Z=W.substr(W.indexOf("#"));Y=B(Z).length>0?"inline":"ajax"}H.type=Y;H.href=W;H.title=ab;if(H.autoDimensions){if(H.type=="html"||H.type=="inline"||H.type=="ajax"){H.width="auto";H.height="auto"}else{H.autoDimensions=false}}if(H.modal){H.overlayShow=true;H.hideOnOverlayClick=false;H.hideOnContentClick=false;H.enableEscapeButton=false;H.showCloseButton=false}H.padding=parseInt(H.padding,10);H.margin=parseInt(H.margin,10);L.css("padding",(H.padding+H.margin));B(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){B(this).replaceWith(m.children())});switch(Y){case"html":L.html(H.content);n();break;case"inline":if(B(Z).parent().is("#fancybox-content")===true){P=false;return}B('<div class="fancybox-inline-tmp" />').hide().insertBefore(B(Z)).bind("fancybox-cleanup",function(){B(this).replaceWith(m.children())}).bind("fancybox-cancel",function(){B(this).replaceWith(L.children())});B(Z).appendTo(L);n();break;case"image":P=false;B.fancybox.showActivity();o=new Image();o.onerror=function(){x()};o.onload=function(){P=true;o.onerror=o.onload=null;F()};o.src=W;break;case"swf":H.scrolling="no";aa='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+H.width+'" height="'+H.height+'"><param name="movie" value="'+W+'"></param>';V="";B.each(H.swf,function(ac,ad){aa+='<param name="'+ac+'" value="'+ad+'"></param>';V+=" "+ac+'="'+ad+'"'});aa+='<embed src="'+W+'" type="application/x-shockwave-flash" width="'+H.width+'" height="'+H.height+'"'+V+"></embed></object>";L.html(aa);n();break;case"ajax":P=false;B.fancybox.showActivity();H.ajax.win=H.ajax.success;f=B.ajax(B.extend({},H.ajax,{url:W,data:H.ajax.data||{},error:function(ac,ae,ad){if(ac.status>0){x()}},success:function(ad,af,ac){var ae=typeof ac=="object"?ac:f;if(ae.status==200){if(typeof H.ajax.win=="function"){X=H.ajax.win(W,ad,af,ac);if(X===false){T.hide();return}else{if(typeof X=="string"||typeof X=="object"){ad=X}}}L.html(ad);n()}}}));break;case"iframe":E();break}},n=function(){var V=H.width,W=H.height;if(V.toString().indexOf("%")>-1){V=parseInt((B(window).width()-(H.margin*2))*parseFloat(V)/100,10)+"px"}else{V=V=="auto"?"auto":V+"px"}if(W.toString().indexOf("%")>-1){W=parseInt((B(window).height()-(H.margin*2))*parseFloat(W)/100,10)+"px"}else{W=W=="auto"?"auto":W+"px"}L.wrapInner('<div style="width:'+V+";height:"+W+";overflow: "+(H.scrolling=="auto"?"auto":(H.scrolling=="yes"?"scroll":"hidden"))+';position:relative;"></div>');H.width=L.width();H.height=L.height();E()},F=function(){H.width=o.width;H.height=o.height;B("<img />").attr({id:"fancybox-img",src:o.src,alt:H.title}).appendTo(L);E()},E=function(){var W,V;T.hide();if(M.is(":visible")&&false===G.onCleanup(y,e,G)){B.event.trigger("fancybox-cancel");P=false;return}P=true;B(m.add(Q)).unbind();B(window).unbind("resize.fb scroll.fb");B(document).unbind("keydown.fb");if(M.is(":visible")&&G.titlePosition!=="outside"){M.css("height",M.height())}y=j;e=C;G=H;if(G.overlayShow){Q.css({"background-color":G.overlayColor,opacity:G.overlayOpacity,cursor:G.hideOnOverlayClick?"pointer":"auto",height:B(document).height()});if(!Q.is(":visible")){if(S){B("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"})}Q.show()}}else{Q.hide()}c=R();l();if(M.is(":visible")){B(J.add(O).add(z)).hide();W=M.position(),b={top:W.top,left:W.left,width:M.width(),height:M.height()};V=(b.width==c.width&&b.height==c.height);m.fadeTo(G.changeFade,0.3,function(){var X=function(){m.html(L.contents()).fadeTo(G.changeFade,1,v)};B.event.trigger("fancybox-change");m.empty().removeAttr("filter").css({"border-width":G.padding,width:c.width-G.padding*2,height:H.autoDimensions?"auto":c.height-h-G.padding*2});if(V){X()}else{s.prop=0;B(s).animate({prop:1},{duration:G.changeSpeed,easing:G.easingChange,step:U,complete:X})}});return}M.removeAttr("style");m.css("border-width",G.padding);if(G.transitionIn=="elastic"){b=I();m.html(L.contents());M.show();if(G.opacity){c.opacity=0}s.prop=0;B(s).animate({prop:1},{duration:G.speedIn,easing:G.easingIn,step:U,complete:v});return}if(G.titlePosition=="inside"&&h>0){A.show()}m.css({width:c.width-G.padding*2,height:H.autoDimensions?"auto":c.height-h-G.padding*2}).html(L.contents());M.css(c).fadeIn(G.transitionIn=="none"?0:G.speedIn,v)},D=function(V){if(V&&V.length){if(G.titlePosition=="float"){return'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+V+'</td><td id="fancybox-title-float-right"></td></tr></table>'}return'<div id="fancybox-title-'+G.titlePosition+'">'+V+"</div>"}return false},l=function(){t=G.title||"";h=0;A.empty().removeAttr("style").removeClass();if(G.titleShow===false){A.hide();return}t=B.isFunction(G.titleFormat)?G.titleFormat(t,y,e,G):D(t);if(!t||t===""){A.hide();return}A.addClass("fancybox-title-"+G.titlePosition).html(t).appendTo("body").show();switch(G.titlePosition){case"inside":A.css({width:c.width-(G.padding*2),marginLeft:G.padding,marginRight:G.padding});h=A.outerHeight(true);A.appendTo(d);c.height+=h;break;case"over":A.css({marginLeft:G.padding,width:c.width-(G.padding*2),bottom:G.padding}).appendTo(d);break;case"float":A.css("left",parseInt((A.width()-c.width-40)/2,10)*-1).appendTo(M);break;default:A.css({width:c.width-(G.padding*2),paddingLeft:G.padding,paddingRight:G.padding}).appendTo(M);break}A.hide()},g=function(){if(G.enableEscapeButton||G.enableKeyboardNav){B(document).bind("keydown.fb",function(V){if(V.keyCode==27&&G.enableEscapeButton){V.preventDefault();B.fancybox.close()}else{if((V.keyCode==37||V.keyCode==39)&&G.enableKeyboardNav&&V.target.tagName!=="INPUT"&&V.target.tagName!=="TEXTAREA"&&V.target.tagName!=="SELECT"){V.preventDefault();B.fancybox[V.keyCode==37?"prev":"next"]()}}})}if(!G.showNavArrows){O.hide();z.hide();return}if((G.cyclic&&y.length>1)||e!==0){O.show()}if((G.cyclic&&y.length>1)||e!=(y.length-1)){z.show()}},v=function(){if(!B.support.opacity){m.get(0).style.removeAttribute("filter");M.get(0).style.removeAttribute("filter")}if(H.autoDimensions){m.css("height","auto")}M.css("height","auto");if(t&&t.length){A.show()}if(G.showCloseButton){J.show()}g();if(G.hideOnContentClick){m.bind("click",B.fancybox.close)}if(G.hideOnOverlayClick){Q.bind("click",B.fancybox.close)}B(window).bind("resize.fb",B.fancybox.resize);if(G.centerOnScroll){B(window).bind("scroll.fb",B.fancybox.center)}if(G.type=="iframe"){B('<iframe id="fancybox-frame" name="fancybox-frame'+new Date().getTime()+'" frameborder="0" hspace="0" '+(B.browser.msie?'allowtransparency="true""':"")+' scrolling="'+H.scrolling+'" src="'+G.href+'"></iframe>').appendTo(m)}M.show();P=false;B.fancybox.center();G.onComplete(y,e,G);K()},K=function(){var V,W;if((y.length-1)>e){V=y[e+1].href;if(typeof V!=="undefined"&&V.match(i)){W=new Image();W.src=V}}if(e>0){V=y[e-1].href;if(typeof V!=="undefined"&&V.match(i)){W=new Image();W.src=V}}},U=function(W){var V={width:parseInt(b.width+(c.width-b.width)*W,10),height:parseInt(b.height+(c.height-b.height)*W,10),top:parseInt(b.top+(c.top-b.top)*W,10),left:parseInt(b.left+(c.left-b.left)*W,10)};if(typeof c.opacity!=="undefined"){V.opacity=W<0.5?0.5:W}M.css(V);m.css({width:V.width-G.padding*2,height:V.height-(h*W)-G.padding*2})},u=function(){return[B(window).width()-(G.margin*2),B(window).height()-(G.margin*2),B(document).scrollLeft()+G.margin,B(document).scrollTop()+G.margin]},R=function(){var V=u(),Z={},W=G.autoScale,X=G.padding*2,Y;if(G.width.toString().indexOf("%")>-1){Z.width=parseInt((V[0]*parseFloat(G.width))/100,10)}else{Z.width=G.width+X}if(G.height.toString().indexOf("%")>-1){Z.height=parseInt((V[1]*parseFloat(G.height))/100,10)}else{Z.height=G.height+X}if(W&&(Z.width>V[0]||Z.height>V[1])){if(H.type=="image"||H.type=="swf"){Y=(G.width)/(G.height);if((Z.width)>V[0]){Z.width=V[0];Z.height=parseInt(((Z.width-X)/Y)+X,10)}if((Z.height)>V[1]){Z.height=V[1];Z.width=parseInt(((Z.height-X)*Y)+X,10)}}else{Z.width=Math.min(Z.width,V[0]);Z.height=Math.min(Z.height,V[1])}}Z.top=parseInt(Math.max(V[3]-20,V[3]+((V[1]-Z.height-40)*0.5)),10);Z.left=parseInt(Math.max(V[2]-20,V[2]+((V[0]-Z.width-40)*0.5)),10);return Z},q=function(V){var W=V.offset();W.top+=parseInt(V.css("paddingTop"),10)||0;W.left+=parseInt(V.css("paddingLeft"),10)||0;W.top+=parseInt(V.css("border-top-width"),10)||0;W.left+=parseInt(V.css("border-left-width"),10)||0;W.width=V.width();W.height=V.height();return W},I=function(){var Y=H.orig?B(H.orig):false,X={},W,V;if(Y&&Y.length){W=q(Y);X={width:W.width+(G.padding*2),height:W.height+(G.padding*2),top:W.top-G.padding-20,left:W.left-G.padding-20}}else{V=u();X={width:G.padding*2,height:G.padding*2,top:parseInt(V[3]+V[1]*0.5,10),left:parseInt(V[2]+V[0]*0.5,10)}}return X},a=function(){if(!T.is(":visible")){clearInterval(p);return}B("div",T).css("top",(N*-40)+"px");N=(N+1)%12};B.fn.fancybox=function(V){if(!B(this).length){return this}B(this).data("fancybox",B.extend({},V,(B.metadata?B(this).metadata():{}))).unbind("click.fb").bind("click.fb",function(X){X.preventDefault();if(P){return}P=true;B(this).blur();j=[];C=0;var W=B(this).attr("rel")||"";if(!W||W==""||W==="nofollow"){j.push(this)}else{j=B("a[rel="+W+"], area[rel="+W+"]");C=j.index(this)}w();return});return this};B.fancybox=function(Y){var X;if(P){return}P=true;X=typeof arguments[1]!=="undefined"?arguments[1]:{};j=[];C=parseInt(X.index,10)||0;if(B.isArray(Y)){for(var W=0,V=Y.length;W<V;W++){if(typeof Y[W]=="object"){B(Y[W]).data("fancybox",B.extend({},X,Y[W]))}else{Y[W]=B({}).data("fancybox",B.extend({content:Y[W]},X))}}j=jQuery.merge(j,Y)}else{if(typeof Y=="object"){B(Y).data("fancybox",B.extend({},X,Y))}else{Y=B({}).data("fancybox",B.extend({content:Y},X))}j.push(Y)}if(C>j.length||C<0){C=0}w()};B.fancybox.showActivity=function(){clearInterval(p);T.show();p=setInterval(a,66)};B.fancybox.hideActivity=function(){T.hide()};B.fancybox.next=function(){return B.fancybox.pos(e+1)};B.fancybox.prev=function(){return B.fancybox.pos(e-1)};B.fancybox.pos=function(V){if(P){return}V=parseInt(V);j=y;if(V>-1&&V<y.length){C=V;w()}else{if(G.cyclic&&y.length>1){C=V>=y.length?0:y.length-1;w()}}return};B.fancybox.cancel=function(){if(P){return}P=true;B.event.trigger("fancybox-cancel");r();H.onCancel(j,C,H);P=false};B.fancybox.close=function(){if(P||M.is(":hidden")){return}P=true;if(G&&false===G.onCleanup(y,e,G)){P=false;return}r();B(J.add(O).add(z)).hide();B(m.add(Q)).unbind();B(window).unbind("resize.fb scroll.fb");B(document).unbind("keydown.fb");m.find("iframe").attr("src",S&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");if(G.titlePosition!=="inside"){A.empty()}M.stop();function V(){Q.fadeOut("fast");A.empty().hide();M.hide();B.event.trigger("fancybox-cleanup");m.empty();G.onClosed(y,e,G);y=H=[];e=C=0;G=H={};P=false}if(G.transitionOut=="elastic"){b=I();var W=M.position();c={top:W.top,left:W.left,width:M.width(),height:M.height()};if(G.opacity){c.opacity=1}A.empty().hide();s.prop=1;B(s).animate({prop:0},{duration:G.speedOut,easing:G.easingOut,step:U,complete:V})}else{M.fadeOut(G.transitionOut=="none"?0:G.speedOut,V)}};B.fancybox.resize=function(){if(Q.is(":visible")){Q.css("height",B(document).height())}B.fancybox.center(true)};B.fancybox.center=function(){var V,W;if(P){return}W=arguments[0]===true?1:0;V=u();if(!W&&(M.width()>V[0]||M.height()>V[1])){return}M.stop().animate({top:parseInt(Math.max(V[3]-20,V[3]+((V[1]-m.height()-40)*0.5)-G.padding)),left:parseInt(Math.max(V[2]-20,V[2]+((V[0]-m.width()-40)*0.5)-G.padding))},typeof arguments[0]=="number"?arguments[0]:200)};B.fancybox.init=function(){if(B("#fancybox-wrap").length){return}B("body").append(L=B('<div id="fancybox-tmp"></div>'),T=B('<div id="fancybox-loading"><div></div></div>'),Q=B('<div id="fancybox-overlay"></div>'),M=B('<div id="fancybox-wrap"></div>'));d=B('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(M);d.append(m=B('<div id="fancybox-content"></div>'),J=B('<a id="fancybox-close"></a>'),A=B('<div id="fancybox-title"></div>'),O=B('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),z=B('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));J.click(B.fancybox.close);T.click(B.fancybox.cancel);O.click(function(V){V.preventDefault();B.fancybox.prev()});z.click(function(V){V.preventDefault();B.fancybox.next()});if(B.fn.mousewheel){M.bind("mousewheel.fb",function(V,W){if(P){V.preventDefault()}else{if(B(V.target).get(0).clientHeight==0||B(V.target).get(0).scrollHeight===B(V.target).get(0).clientHeight){V.preventDefault();B.fancybox[W>0?"prev":"next"]()}}})}if(!B.support.opacity){M.addClass("fancybox-ie")}if(S){T.addClass("fancybox-ie6");M.addClass("fancybox-ie6");B('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(d)}};B.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};B(document).ready(function(){B.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php
index 32fd2124429..fc0d272b54e 100644
--- a/apps/files_sharing/sharedstorage.php
+++ b/apps/files_sharing/sharedstorage.php
@@ -410,7 +410,7 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common {
}
}
- public function hash($type, $path, $raw) {
+ public function hash($type, $path, $raw = false) {
$source = $this->getSource($path);
if ($source) {
$storage = OC_Filesystem::getStorage($source);
diff --git a/apps/gallery/l10n/de.php b/apps/gallery/l10n/de.php
index 6c3d9fc7389..cd580cf303c 100644
--- a/apps/gallery/l10n/de.php
+++ b/apps/gallery/l10n/de.php
@@ -1,9 +1,9 @@
<?php $TRANSLATIONS = array(
"Pictures" => "Bilder",
-"Settings" => "Einstellungen",
-"Rescan" => "Erneut Scannen",
-"Stop" => "Stopp",
-"Share" => "Teilen",
+"Share gallery" => "Galerie teilen",
+"Error: " => "Fehler:",
+"Internal error" => "Interner Fehler",
+"Slideshow" => "Slideshow",
"Back" => "Zurück",
"Remove confirmation" => "Bestätigung entfernen",
"Do you want to remove album" => "Soll das Album entfernt werden",
diff --git a/apps/gallery/l10n/es.php b/apps/gallery/l10n/es.php
index 03e8d6a4563..aa425a0bd04 100644
--- a/apps/gallery/l10n/es.php
+++ b/apps/gallery/l10n/es.php
@@ -1,9 +1,9 @@
<?php $TRANSLATIONS = array(
"Pictures" => "Imágenes",
-"Settings" => "Preferencias",
-"Rescan" => "Refrescar",
-"Stop" => "Parar",
-"Share" => "Compartir",
+"Share gallery" => "Compartir galería",
+"Error: " => "Fallo ",
+"Internal error" => "Fallo interno",
+"Slideshow" => "Presentación",
"Back" => "Atrás",
"Remove confirmation" => "Borrar confirmación",
"Do you want to remove album" => "¿Quieres eliminar el álbum",
diff --git a/apps/gallery/l10n/it.php b/apps/gallery/l10n/it.php
index e21a1d6524b..ef8d596e7eb 100644
--- a/apps/gallery/l10n/it.php
+++ b/apps/gallery/l10n/it.php
@@ -1,9 +1,9 @@
<?php $TRANSLATIONS = array(
"Pictures" => "Immagini",
-"Settings" => "Impostazioni",
-"Rescan" => "Nuova scansione",
-"Stop" => "Ferma",
-"Share" => "Condividi",
+"Share gallery" => "Condividi la galleria",
+"Error: " => "Errore: ",
+"Internal error" => "Errore interno",
+"Slideshow" => "Presentazione",
"Back" => "Indietro",
"Remove confirmation" => "Rimuovi conferma",
"Do you want to remove album" => "Vuoi rimuovere l'album",
diff --git a/apps/gallery/l10n/vi.php b/apps/gallery/l10n/vi.php
new file mode 100644
index 00000000000..d1d7fc64fca
--- /dev/null
+++ b/apps/gallery/l10n/vi.php
@@ -0,0 +1,11 @@
+<?php $TRANSLATIONS = array(
+"Pictures" => "Hình ảnh",
+"Share gallery" => "Chia sẻ gallery",
+"Error: " => "Lỗi :",
+"Internal error" => "Lỗi nội bộ",
+"Back" => "Trở lại",
+"Remove confirmation" => "Xóa xác nhận",
+"Do you want to remove album" => "Bạn muốn xóa album này ",
+"Change album name" => "Đổi tên album",
+"New album name" => "Tên album mới"
+);
diff --git a/apps/media/l10n/vi.php b/apps/media/l10n/vi.php
new file mode 100644
index 00000000000..01942ba173f
--- /dev/null
+++ b/apps/media/l10n/vi.php
@@ -0,0 +1,14 @@
+<?php $TRANSLATIONS = array(
+"Music" => "Âm nhạc",
+"Add album to playlist" => "Thêm album vào playlist",
+"Play" => "Play",
+"Pause" => "Tạm dừng",
+"Previous" => "Trang trước",
+"Next" => "Tiếp theo",
+"Mute" => "Tắt",
+"Unmute" => "Bật",
+"Rescan Collection" => "Quét lại bộ sưu tập",
+"Artist" => "Nghệ sỹ",
+"Album" => "Album",
+"Title" => "Tiêu đề"
+);
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 330574c1d42..3c6da47d71a 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -21,15 +21,17 @@
*
*/
-require_once('apps/user_ldap/lib_ldap.php');
-require_once('apps/user_ldap/user_ldap.php');
-require_once('apps/user_ldap/group_ldap.php');
+OCP\App::registerAdmin('user_ldap', 'settings');
-OCP\App::registerAdmin('user_ldap','settings');
+$connector = new OCA\user_ldap\lib\Connection('user_ldap');
+$userBackend = new OCA\user_ldap\USER_LDAP();
+$userBackend->setConnector($connector);
+$groupBackend = new OCA\user_ldap\GROUP_LDAP();
+$groupBackend->setConnector($connector);
// register user backend
-OC_User::useBackend( 'LDAP' );
-OC_Group::useBackend( new OC_GROUP_LDAP() );
+OC_User::useBackend($userBackend);
+OC_Group::useBackend($groupBackend);
// add settings page to navigation
$entry = array(
diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php
index d438c7d84df..b9f4bdf1990 100644
--- a/apps/user_ldap/group_ldap.php
+++ b/apps/user_ldap/group_ldap.php
@@ -21,24 +21,22 @@
*
*/
-class OC_GROUP_LDAP extends OC_Group_Backend {
-// //group specific settings
- protected $ldapGroupFilter;
- protected $ldapGroupMemberAssocAttr;
- protected $configured = false;
+namespace OCA\user_ldap;
+
+class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
+ protected $enabled = false;
protected $_group_user = array();
protected $_user_groups = array();
protected $_group_users = array();
protected $_groups = array();
- public function __construct() {
- $this->ldapGroupFilter = OCP\Config::getAppValue('user_ldap', 'ldap_group_filter', '(objectClass=posixGroup)');
- $this->ldapGroupMemberAssocAttr = OCP\Config::getAppValue('user_ldap', 'ldap_group_member_assoc_attribute', 'uniqueMember');
-
- if(!empty($this->ldapGroupFilter) && !empty($this->ldapGroupMemberAssocAttr)) {
- $this->configured = true;
+ public function setConnector(lib\Connection &$connection) {
+ parent::setConnector($connection);
+ if(empty($this->connection->ldapGroupFilter) || empty($this->connection->ldapGroupMemberAssocAttr)) {
+ $this->enabled = false;
}
+ $this->enabled = true;
}
/**
@@ -50,31 +48,31 @@ class OC_GROUP_LDAP extends OC_Group_Backend {
* Checks whether the user is member of a group or not.
*/
public function inGroup($uid, $gid) {
- if(!$this->configured) {
+ if(!$this->enabled) {
return false;
}
if(isset($this->_group_user[$gid][$uid])) {
return $this->_group_user[$gid][$uid];
}
- $dn_user = OC_LDAP::username2dn($uid);
- $dn_group = OC_LDAP::groupname2dn($gid);
+ $dn_user = $this->username2dn($uid);
+ $dn_group = $this->groupname2dn($gid);
// just in case
if(!$dn_group || !$dn_user) {
return false;
}
//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
- $members = OC_LDAP::readAttribute($dn_group, $this->ldapGroupMemberAssocAttr);
+ $members = $this->readAttribute($dn_group, $this->connection->ldapGroupMemberAssocAttr);
if(!$members) {
return false;
}
//extra work if we don't get back user DNs
//TODO: this can be done with one LDAP query
- if(strtolower($this->ldapGroupMemberAssocAttr) == 'memberuid') {
+ if(strtolower($this->connection->ldapGroupMemberAssocAttr) == 'memberuid') {
$dns = array();
foreach($members as $mid) {
- $filter = str_replace('%uid', $mid, OC_LDAP::conf('ldapLoginFilter'));
- $ldap_users = OC_LDAP::fetchListOfUsers($filter, 'dn');
+ $filter = str_replace('%uid', $mid, $this->connection->ldapLoginFilter);
+ $ldap_users = $this->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
continue;
}
@@ -96,36 +94,37 @@ class OC_GROUP_LDAP extends OC_Group_Backend {
* if the user exists at all.
*/
public function getUserGroups($uid) {
- if(!$this->configured) {
+ if(!$this->enabled) {
return array();
}
if(isset($this->_user_groups[$uid])) {
return $this->_user_groups[$uid];
}
- $userDN = OC_LDAP::username2dn($uid);
+ $userDN = $this->username2dn($uid);
if(!$userDN) {
$this->_user_groups[$uid] = array();
return array();
}
//uniqueMember takes DN, memberuid the uid, so we need to distinguish
- if((strtolower($this->ldapGroupMemberAssocAttr) == 'uniquemember')
- || (strtolower($this->ldapGroupMemberAssocAttr) == 'member')) {
+ if((strtolower($this->connection->ldapGroupMemberAssocAttr) == 'uniquemember')
+ || (strtolower($this->connection->ldapGroupMemberAssocAttr) == 'member')
+ ) {
$uid = $userDN;
- } else if(strtolower($this->ldapGroupMemberAssocAttr) == 'memberuid') {
- $result = OC_LDAP::readAttribute($userDN, 'uid');
+ } else if(strtolower($this->connection->ldapGroupMemberAssocAttr) == 'memberuid') {
+ $result = $this->readAttribute($userDN, 'uid');
$uid = $result[0];
} else {
// just in case
$uid = $userDN;
}
- $filter = OC_LDAP::combineFilterWithAnd(array(
- $this->ldapGroupFilter,
- $this->ldapGroupMemberAssocAttr.'='.$uid
+ $filter = $this->combineFilterWithAnd(array(
+ $this->connection->ldapGroupFilter,
+ $this->connection->ldapGroupMemberAssocAttr.'='.$uid
));
- $groups = OC_LDAP::fetchListOfGroups($filter, array(OC_LDAP::conf('ldapGroupDisplayName'),'dn'));
- $this->_user_groups[$uid] = array_unique(OC_LDAP::ownCloudGroupNames($groups), SORT_LOCALE_STRING);
+ $groups = $this->fetchListOfGroups($filter, array($this->connection->ldapGroupDisplayName,'dn'));
+ $this->_user_groups[$uid] = array_unique($this->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
return $this->_user_groups[$uid];
}
@@ -135,44 +134,44 @@ class OC_GROUP_LDAP extends OC_Group_Backend {
* @returns array with user ids
*/
public function usersInGroup($gid) {
- if(!$this->configured) {
+ if(!$this->enabled) {
return array();
}
if(isset($this->_group_users[$gid])) {
return $this->_group_users[$gid];
}
- $groupDN = OC_LDAP::groupname2dn($gid);
+ $groupDN = $this->groupname2dn($gid);
if(!$groupDN) {
$this->_group_users[$gid] = array();
return array();
}
- $members = OC_LDAP::readAttribute($groupDN, $this->ldapGroupMemberAssocAttr);
+ $members = $this->readAttribute($groupDN, $this->connection->ldapGroupMemberAssocAttr);
if(!$members) {
$this->_group_users[$gid] = array();
return array();
}
$result = array();
- $isMemberUid = (strtolower($this->ldapGroupMemberAssocAttr) == 'memberuid');
+ $isMemberUid = (strtolower($this->connection->ldapGroupMemberAssocAttr) == 'memberuid');
foreach($members as $member) {
if($isMemberUid) {
- $filter = OCP\Util::mb_str_replace('%uid', $member, OC_LDAP::conf('ldapLoginFilter'), 'UTF-8');
- $ldap_users = OC_LDAP::fetchListOfUsers($filter, 'dn');
+ $filter = \OCP\Util::mb_str_replace('%uid', $member, $this->connection->ldapLoginFilter, 'UTF-8');
+ $ldap_users = $this->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
continue;
}
- $result[] = OC_LDAP::dn2username($ldap_users[0]);
+ $result[] = $this->dn2username($ldap_users[0]);
continue;
} else {
- if($ocname = OC_LDAP::dn2username($member)){
+ if($ocname = $this->dn2username($member)) {
$result[] = $ocname;
}
}
}
if(!$isMemberUid) {
- $result = array_intersect($result, OCP\User::getUsers());
+ $result = array_intersect($result, \OCP\User::getUsers());
}
$this->_group_users[$gid] = array_unique($result, SORT_LOCALE_STRING);
return $this->_group_users[$gid];
@@ -185,12 +184,12 @@ class OC_GROUP_LDAP extends OC_Group_Backend {
* Returns a list with all groups
*/
public function getGroups() {
- if(!$this->configured) {
+ if(!$this->enabled) {
return array();
}
if(empty($this->_groups)) {
- $ldap_groups = OC_LDAP::fetchListOfGroups($this->ldapGroupFilter, array(OC_LDAP::conf('ldapGroupDisplayName'), 'dn'));
- $this->_groups = OC_LDAP::ownCloudGroupNames($ldap_groups);
+ $ldap_groups = $this->fetchListOfGroups($this->connection->ldapGroupFilter, array($this->connection->ldapGroupDisplayName, 'dn'));
+ $this->_groups = $this->ownCloudGroupNames($ldap_groups);
}
return $this->_groups;
}
@@ -203,4 +202,17 @@ class OC_GROUP_LDAP extends OC_Group_Backend {
public function groupExists($gid){
return in_array($gid, $this->getGroups());
}
+
+ /**
+ * @brief Check if backend implements actions
+ * @param $actions bitwise-or'ed actions
+ * @returns boolean
+ *
+ * Returns the supported actions as int to be
+ * compared with OC_USER_BACKEND_CREATE_USER etc.
+ */
+ public function implementsActions($actions) {
+ //always returns false, because possible actions are modifying actions. We do not write to LDAP, at least for now.
+ return false;
+ }
} \ No newline at end of file
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
new file mode 100644
index 00000000000..19122b34c7d
--- /dev/null
+++ b/apps/user_ldap/lib/access.php
@@ -0,0 +1,597 @@
+<?php
+
+/**
+ * ownCloud – LDAP Access
+ *
+ * @author Arthur Schiwon
+ * @copyright 2012 Arthur Schiwon blizzz@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\user_ldap\lib;
+
+abstract class Access {
+ protected $connection;
+
+ public function setConnector(Connection &$connection) {
+ $this->connection = $connection;
+ }
+
+ private function checkConnection() {
+ return ($this->connection instanceof Connection);
+ }
+
+ /**
+ * @brief reads a given attribute for an LDAP record identified by a DN
+ * @param $dn the record in question
+ * @param $attr the attribute that shall be retrieved
+ * @returns the values in an array on success, false otherwise
+ *
+ * Reads an attribute from an LDAP entry
+ */
+ public function readAttribute($dn, $attr) {
+ if(!$this->checkConnection()) {
+ \OCP\Util::writeLog('user_ldap', 'No LDAP Connector assigned, access impossible for readAttribute.', \OCP\Util::WARN);
+ return false;
+ }
+ $cr = $this->connection->getConnectionResource();
+ if(!is_resource($cr)) {
+ //LDAP not available
+ return false;
+ }
+ $rr = @ldap_read($cr, $dn, 'objectClass=*', array($attr));
+ if(!is_resource($rr)) {
+ \OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN '.$dn, \OCP\Util::DEBUG);
+ //in case an error occurs , e.g. object does not exist
+ return false;
+ }
+ $er = ldap_first_entry($cr, $rr);
+ //LDAP attributes are not case sensitive
+ $result = \OCP\Util::mb_array_change_key_case(ldap_get_attributes($cr, $er), MB_CASE_LOWER, 'UTF-8');
+ $attr = mb_strtolower($attr, 'UTF-8');
+
+ if(isset($result[$attr]) && $result[$attr]['count'] > 0) {
+ $values = array();
+ for($i=0;$i<$result[$attr]['count'];$i++) {
+ $values[] = $this->resemblesDN($attr) ? $this->sanitizeDN($result[$attr][$i]) : $result[$attr][$i];
+ }
+ return $values;
+ }
+ return false;
+ }
+
+ /**
+ * @brief checks wether the given attribute`s valua is probably a DN
+ * @param $attr the attribute in question
+ * @return if so true, otherwise false
+ */
+ private function resemblesDN($attr) {
+ $resemblingAttributes = array(
+ 'dn',
+ 'uniquemember',
+ 'member'
+ );
+ return in_array($attr, $resemblingAttributes);
+ }
+
+ /**
+ * @brief sanitizes a DN received from the LDAP server
+ * @param $dn the DN in question
+ * @return the sanitized DN
+ */
+ private function sanitizeDN($dn) {
+ //OID sometimes gives back DNs with whitespace after the comma a la "uid=foo, cn=bar, dn=..." We need to tackle this!
+ $dn = preg_replace('/([^\\\]),(\s+)/u', '\1,', $dn);
+
+ //make comparisons and everything work
+ $dn = mb_strtolower($dn, 'UTF-8');
+
+ return $dn;
+ }
+
+ /**
+ * gives back the database table for the query
+ */
+ private function getMapTable($isUser) {
+ if($isUser) {
+ return '*PREFIX*ldap_user_mapping';
+ } else {
+ return '*PREFIX*ldap_group_mapping';
+ }
+ }
+
+ /**
+ * @brief returns the LDAP DN for the given internal ownCloud name of the group
+ * @param $name the ownCloud name in question
+ * @returns string with the LDAP DN on success, otherwise false
+ *
+ * returns the LDAP DN for the given internal ownCloud name of the group
+ */
+ public function groupname2dn($name) {
+ return $this->ocname2dn($name, false);
+ }
+
+ /**
+ * @brief returns the LDAP DN for the given internal ownCloud name of the user
+ * @param $name the ownCloud name in question
+ * @returns string with the LDAP DN on success, otherwise false
+ *
+ * returns the LDAP DN for the given internal ownCloud name of the user
+ */
+ public function username2dn($name) {
+ $dn = $this->ocname2dn($name, true);
+ if($dn) {
+ return $dn;
+ } else {
+ //fallback: user is not mapped
+ $filter = $this->combineFilterWithAnd(array(
+ $this->connection->ldapUserFilter,
+ $this->connection->ldapUserDisplayName . '=' . $name,
+ ));
+ $result = $this->searchUsers($filter, 'dn');
+ if(isset($result[0]['dn'])) {
+ $this->mapComponent($result[0], $name, true);
+ return $result[0];
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @brief returns the LDAP DN for the given internal ownCloud name
+ * @param $name the ownCloud name in question
+ * @param $isUser is it a user? otherwise group
+ * @returns string with the LDAP DN on success, otherwise false
+ *
+ * returns the LDAP DN for the given internal ownCloud name
+ */
+ private function ocname2dn($name, $isUser) {
+ $table = $this->getMapTable($isUser);
+
+ $query = \OCP\DB::prepare('
+ SELECT ldap_dn
+ FROM '.$table.'
+ WHERE owncloud_name = ?
+ ');
+
+ $record = $query->execute(array($name))->fetchOne();
+ return $record;
+ }
+
+ /**
+ * @brief returns the internal ownCloud name for the given LDAP DN of the group
+ * @param $dn the dn of the group object
+ * @param $ldapname optional, the display name of the object
+ * @returns string with with the name to use in ownCloud, false on DN outside of search DN
+ *
+ * returns the internal ownCloud name for the given LDAP DN of the group
+ */
+ public function dn2groupname($dn, $ldapname = null) {
+ if(mb_strripos($dn, $this->connection->ldapBaseGroups, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen($this->connection->ldapBaseGroups, 'UTF-8'))) {
+ return false;
+ }
+ return $this->dn2ocname($dn, $ldapname, false);
+ }
+
+ /**
+ * @brief returns the internal ownCloud name for the given LDAP DN of the user
+ * @param $dn the dn of the user object
+ * @param $ldapname optional, the display name of the object
+ * @returns string with with the name to use in ownCloud
+ *
+ * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN
+ */
+ public function dn2username($dn, $ldapname = null) {
+ if(mb_strripos($dn, $this->connection->ldapBaseUsers, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen($this->connection->ldapBaseUsers, 'UTF-8'))) {
+ return false;
+ }
+ return $this->dn2ocname($dn, $ldapname, true);
+ }
+
+ /**
+ * @brief returns an internal ownCloud name for the given LDAP DN
+ * @param $dn the dn of the user object
+ * @param $ldapname optional, the display name of the object
+ * @param $isUser optional, wether it is a user object (otherwise group assumed)
+ * @returns string with with the name to use in ownCloud
+ *
+ * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN
+ */
+ public function dn2ocname($dn, $ldapname = null, $isUser = true) {
+ $dn = $this->sanitizeDN($dn);
+ $table = $this->getMapTable($isUser);
+ if($isUser) {
+ $nameAttribute = $this->connection->ldapUserDisplayName;
+ } else {
+ $nameAttribute = $this->connection->ldapGroupDisplayName;
+ }
+
+ $query = \OCP\DB::prepare('
+ SELECT owncloud_name
+ FROM '.$table.'
+ WHERE ldap_dn = ?
+ ');
+
+ $component = $query->execute(array($dn))->fetchOne();
+ if($component) {
+ return $component;
+ }
+
+ if(is_null($ldapname)) {
+ $ldapname = $this->readAttribute($dn, $nameAttribute);
+ $ldapname = $ldapname[0];
+ }
+ $ldapname = $this->sanitizeUsername($ldapname);
+
+ //a new user/group! Then let's try to add it. We're shooting into the blue with the user/group name, assuming that in most cases there will not be a conflict. Otherwise an error will occur and we will continue with our second shot.
+ if($this->mapComponent($dn, $ldapname, $isUser)) {
+ return $ldapname;
+ }
+
+ //doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located.
+ $oc_name = $this->alternateOwnCloudName($ldapname, $dn);
+ if($this->mapComponent($dn, $oc_name, $isUser)) {
+ return $oc_name;
+ }
+
+ //TODO: do not simple die away!
+ //and this of course should never been thrown :)
+ throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.');
+ }
+
+ /**
+ * @brief gives back the user names as they are used ownClod internally
+ * @param $ldapGroups an array with the ldap Users result in style of array ( array ('dn' => foo, 'uid' => bar), ... )
+ * @returns an array with the user names to use in ownCloud
+ *
+ * gives back the user names as they are used ownClod internally
+ */
+ public function ownCloudUserNames($ldapUsers) {
+ return $this->ldap2ownCloudNames($ldapUsers, true);
+ }
+
+ /**
+ * @brief gives back the group names as they are used ownClod internally
+ * @param $ldapGroups an array with the ldap Groups result in style of array ( array ('dn' => foo, 'cn' => bar), ... )
+ * @returns an array with the group names to use in ownCloud
+ *
+ * gives back the group names as they are used ownClod internally
+ */
+ public function ownCloudGroupNames($ldapGroups) {
+ return $this->ldap2ownCloudNames($ldapGroups, false);
+ }
+
+ private function ldap2ownCloudNames($ldapObjects, $isUsers) {
+ if($isUsers) {
+ $knownObjects = $this->mappedUsers();
+ $nameAttribute = $this->connection->ldapUserDisplayName;
+ } else {
+ $knownObjects = $this->mappedGroups();
+ $nameAttribute = $this->connection->ldapGroupDisplayName;
+ }
+ $ownCloudNames = array();
+
+ foreach($ldapObjects as $ldapObject) {
+ $key = \OCP\Util::recursiveArraySearch($knownObjects, $ldapObject['dn']);
+
+ //everything is fine when we know the group
+ if($key !== false) {
+ $ownCloudNames[] = $knownObjects[$key]['owncloud_name'];
+ continue;
+ }
+
+ //a new group! Then let's try to add it. We're shooting into the blue with the group name, assuming that in most cases there will not be a conflict. But first make sure, that the display name contains only allowed characters.
+ $ocname = $this->sanitizeUsername($ldapObject[$nameAttribute]);
+ if($this->mapComponent($ldapObject['dn'], $ocname, $isUsers)) {
+ $ownCloudNames[] = $ocname;
+ continue;
+ }
+
+ //doh! There is a conflict. We need to distinguish between groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this entry is located.
+ $ocname = $this->alternateOwnCloudName($ocname, $ldapObject['dn']);
+ if($this->mapComponent($ldapObject['dn'], $ocname, $isUsers)) {
+ $ownCloudNames[] = $ocname;
+ continue;
+ }
+
+ //TODO: do not simple die away
+ //and this of course should never been thrown :)
+ throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.');
+ }
+ return $ownCloudNames;
+ }
+
+ /**
+ * @brief creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
+ * @param $name the display name of the object
+ * @param $dn the dn of the object
+ * @returns string with with the name to use in ownCloud
+ *
+ * creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
+ */
+ private function alternateOwnCloudName($name, $dn) {
+ $ufn = ldap_dn2ufn($dn);
+ $name = $name . '@' . trim(\OCP\Util::mb_substr_replace($ufn, '', 0, mb_strpos($ufn, ',', 0, 'UTF-8'), 'UTF-8'));
+ $name = $this->sanitizeUsername($name);
+ return $name;
+ }
+
+ /**
+ * @brief retrieves all known groups from the mappings table
+ * @returns array with the results
+ *
+ * retrieves all known groups from the mappings table
+ */
+ private function mappedGroups() {
+ return $this->mappedComponents(false);
+ }
+
+ /**
+ * @brief retrieves all known users from the mappings table
+ * @returns array with the results
+ *
+ * retrieves all known users from the mappings table
+ */
+ private function mappedUsers() {
+ return $this->mappedComponents(true);
+ }
+
+ private function mappedComponents($isUsers) {
+ $table = $this->getMapTable($isUsers);
+
+ $query = \OCP\DB::prepare('
+ SELECT ldap_dn, owncloud_name
+ FROM '. $table
+ );
+
+ return $query->execute()->fetchAll();
+ }
+
+ /**
+ * @brief inserts a new user or group into the mappings table
+ * @param $dn the record in question
+ * @param $ocname the name to use in ownCloud
+ * @param $isUser is it a user or a group?
+ * @returns true on success, false otherwise
+ *
+ * inserts a new user or group into the mappings table
+ */
+ private function mapComponent($dn, $ocname, $isUser = true) {
+ $table = $this->getMapTable($isUser);
+ $dn = $this->sanitizeDN($dn);
+
+ $sqlAdjustment = '';
+ $dbtype = \OCP\Config::getSystemValue('dbtype');
+ if($dbtype == 'mysql') {
+ $sqlAdjustment = 'FROM dual';
+ }
+
+ $insert = \OCP\DB::prepare('
+ INSERT INTO '.$table.' (ldap_dn, owncloud_name)
+ SELECT ?,?
+ '.$sqlAdjustment.'
+ WHERE NOT EXISTS (
+ SELECT 1
+ FROM '.$table.'
+ WHERE ldap_dn = ?
+ OR owncloud_name = ? )
+ ');
+
+ $res = $insert->execute(array($dn, $ocname, $dn, $ocname));
+
+ if(\OCP\DB::isError($res)) {
+ return false;
+ }
+
+ $insRows = $res->numRows();
+
+ if($insRows == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function fetchListOfUsers($filter, $attr) {
+ return $this->fetchList($this->searchUsers($filter, $attr), (count($attr) > 1));
+ }
+
+ public function fetchListOfGroups($filter, $attr) {
+ return $this->fetchList($this->searchGroups($filter, $attr), (count($attr) > 1));
+ }
+
+ private function fetchList($list, $manyAttributes) {
+ if(is_array($list)) {
+ if($manyAttributes) {
+ return $list;
+ } else {
+ return array_unique($list, SORT_LOCALE_STRING);
+ }
+ }
+
+ //error cause actually, maybe throw an exception in future.
+ return array();
+ }
+
+ /**
+ * @brief executes an LDAP search, optimized for Users
+ * @param $filter the LDAP filter for the search
+ * @param $attr optional, when a certain attribute shall be filtered out
+ * @returns array with the search result
+ *
+ * Executes an LDAP search
+ */
+ public function searchUsers($filter, $attr = null) {
+ return $this->search($filter, $this->connection->ldapBaseUsers, $attr);
+ }
+
+ /**
+ * @brief executes an LDAP search, optimized for Groups
+ * @param $filter the LDAP filter for the search
+ * @param $attr optional, when a certain attribute shall be filtered out
+ * @returns array with the search result
+ *
+ * Executes an LDAP search
+ */
+ public function searchGroups($filter, $attr = null) {
+ return $this->search($filter, $this->connection->ldapBaseGroups, $attr);
+ }
+
+ /**
+ * @brief executes an LDAP search
+ * @param $filter the LDAP filter for the search
+ * @param $base the LDAP subtree that shall be searched
+ * @param $attr optional, when a certain attribute shall be filtered out
+ * @returns array with the search result
+ *
+ * Executes an LDAP search
+ */
+ private function search($filter, $base, $attr = null) {
+ if(!is_null($attr) && !is_array($attr)) {
+ $attr = array(mb_strtolower($attr, 'UTF-8'));
+ }
+
+ // See if we have a resource
+ $link_resource = $this->connection->getConnectionResource();
+ if(is_resource($link_resource)) {
+ $sr = ldap_search($link_resource, $base, $filter, $attr);
+ $findings = ldap_get_entries($link_resource, $sr );
+
+ // if we're here, probably no connection resource is returned.
+ // to make ownCloud behave nicely, we simply give back an empty array.
+ if(is_null($findings)) {
+ return array();
+ }
+ } else {
+ // Seems like we didn't find any resource.
+ // Return an empty array just like before.
+ \OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
+ return array();
+ }
+
+ if(!is_null($attr)) {
+ $selection = array();
+ $multiarray = false;
+ if(count($attr) > 1) {
+ $multiarray = true;
+ $i = 0;
+ }
+ foreach($findings as $item) {
+ if(!is_array($item)) {
+ continue;
+ }
+ $item = \OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8');
+
+ if($multiarray) {
+ foreach($attr as $key) {
+ $key = mb_strtolower($key, 'UTF-8');
+ if(isset($item[$key])) {
+ if($key != 'dn') {
+ $selection[$i][$key] = $this->resemblesDN($key) ? $this->sanitizeDN($item[$key][0]) : $item[$key][0];
+ } else {
+ $selection[$i][$key] = $this->sanitizeDN($item[$key]);
+ }
+ }
+
+ }
+ $i++;
+ } else {
+ //tribute to case insensitivity
+ $key = mb_strtolower($attr[0], 'UTF-8');
+
+ if(isset($item[$key])) {
+ if($this->resemblesDN($key)) {
+ $selection[] = $this->sanitizeDN($item[$key]);
+ } else {
+ $selection[] = $item[$key];
+ }
+ }
+ }
+ }
+ return $selection;
+ }
+ return $findings;
+ }
+
+ public function sanitizeUsername($name) {
+ if($this->connection->ldapIgnoreNamingRules) {
+ return $name;
+ }
+
+ //REPLACEMENTS
+ $name = \OCP\Util::mb_str_replace(' ', '_', $name, 'UTF-8');
+
+ //every remaining unallowed characters will be removed
+ $name = preg_replace('/[^a-zA-Z0-9_.@-]/u', '', $name);
+
+ return $name;
+ }
+
+ /**
+ * @brief combines the input filters with AND
+ * @param $filters array, the filters to connect
+ * @returns the combined filter
+ *
+ * Combines Filter arguments with AND
+ */
+ public function combineFilterWithAnd($filters) {
+ return $this->combineFilter($filters, '&');
+ }
+
+ /**
+ * @brief combines the input filters with AND
+ * @param $filters array, the filters to connect
+ * @returns the combined filter
+ *
+ * Combines Filter arguments with AND
+ */
+ public function combineFilterWithOr($filters) {
+ return $this->combineFilter($filters, '|');
+ }
+
+ /**
+ * @brief combines the input filters with given operator
+ * @param $filters array, the filters to connect
+ * @param $operator either & or |
+ * @returns the combined filter
+ *
+ * Combines Filter arguments with AND
+ */
+ private function combineFilter($filters, $operator) {
+ $combinedFilter = '('.$operator;
+ foreach($filters as $filter) {
+ if($filter[0] != '(') {
+ $filter = '('.$filter.')';
+ }
+ $combinedFilter.=$filter;
+ }
+ $combinedFilter.=')';
+ return $combinedFilter;
+ }
+
+ public function areCredentialsValid($name, $password) {
+ $testConnection = clone $this->connection;
+ $credentials = array(
+ 'ldapAgentName' => $name,
+ 'ldapAgentPassword' => $password
+ );
+ if(!$testConnection->setConfiguration($credentials)) {
+ return false;
+ }
+ return $testConnection->bind();
+ }
+} \ No newline at end of file
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
new file mode 100644
index 00000000000..e54a8e2b241
--- /dev/null
+++ b/apps/user_ldap/lib/connection.php
@@ -0,0 +1,255 @@
+<?php
+
+/**
+ * ownCloud – LDAP Access
+ *
+ * @author Arthur Schiwon
+ * @copyright 2012 Arthur Schiwon blizzz@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\user_ldap\lib;
+
+class Connection {
+ private $ldapConnectionRes = null;
+ private $configID;
+ private $configured = false;
+
+ //cached settings
+ protected $config = array(
+ 'ldapHost' => null,
+ 'ldapPort' => null,
+ 'ldapBase' => null,
+ 'ldapBaseUsers' => null,
+ 'ldapBaseGroups' => null,
+ 'ldapAgentName' => null,
+ 'ldapAgentPassword' => null,
+ 'ldapTLS' => null,
+ 'ldapNoCase' => null,
+ 'ldapIgnoreNamingRules' => null,
+ 'ldapUserDisplayName' => null,
+ 'ldapUserFilter' => null,
+ 'ldapGroupFilter' => null,
+ 'ldapGroupDisplayName' => null,
+ 'ldapLoginFilter' => null,
+ 'ldapQuotaAttribute' => null,
+ 'ldapQuotaDefault' => null,
+ 'ldapEmailAttribute' => null,
+ );
+
+ public function __construct($configID = 'user_ldap') {
+ $this->configID = $configID;
+ }
+
+ public function __destruct() {
+ @ldap_unbind($this->ldapConnectionRes);
+ }
+
+ public function __get($name) {
+ if(!$this->configured) {
+ $this->readConfiguration();
+ }
+
+ if(isset($this->config[$name])) {
+ return $this->config[$name];
+ }
+ }
+
+ /**
+ * @brief initializes the LDAP backend
+ * @param $force read the config settings no matter what
+ *
+ * initializes the LDAP backend
+ */
+ public function init($force = false) {
+ $this->readConfiguration($force);
+ $this->establishConnection();
+ }
+
+ /**
+ * Returns the LDAP handler
+ */
+ public function getConnectionResource() {
+ if(!$this->ldapConnectionRes) {
+ $this->init();
+ }
+ if(is_null($this->ldapConnectionRes)) {
+ \OCP\Util::writeLog('user_ldap', 'Connection could not be established', \OCP\Util::ERROR);
+ }
+ return $this->ldapConnectionRes;
+ }
+
+ /**
+ * Caches the general LDAP configuration.
+ */
+ private function readConfiguration($force = false) {
+ \OCP\Util::writeLog('user_ldap','Checking conf state: isConfigured? '.print_r($this->configured, true).' isForce? '.print_r($force, true).' configID? '.print_r($this->configID, true), \OCP\Util::DEBUG);
+ if((!$this->configured || $force) && !is_null($this->configID)) {
+ \OCP\Util::writeLog('user_ldap','Reading the configuration', \OCP\Util::DEBUG);
+ $this->config['ldapHost'] = \OCP\Config::getAppValue($this->configID, 'ldap_host', '');
+ $this->config['ldapPort'] = \OCP\Config::getAppValue($this->configID, 'ldap_port', 389);
+ $this->config['ldapAgentName'] = \OCP\Config::getAppValue($this->configID, 'ldap_dn','');
+ $this->config['ldapAgentPassword'] = base64_decode(\OCP\Config::getAppValue($this->configID, 'ldap_agent_password',''));
+ $this->config['ldapBase'] = \OCP\Config::getAppValue($this->configID, 'ldap_base', '');
+ $this->config['ldapBaseUsers'] = \OCP\Config::getAppValue($this->configID, 'ldap_base_users',$this->config['ldapBase']);
+ $this->config['ldapBaseGroups'] = \OCP\Config::getAppValue($this->configID, 'ldap_base_groups', $this->config['ldapBase']);
+ $this->config['ldapTLS'] = \OCP\Config::getAppValue($this->configID, 'ldap_tls',0);
+ $this->config['ldapNoCase'] = \OCP\Config::getAppValue($this->configID, 'ldap_nocase', 0);
+ $this->config['ldapUserDisplayName'] = mb_strtolower(\OCP\Config::getAppValue($this->configID, 'ldap_display_name', 'uid'), 'UTF-8');
+ $this->config['ldapUserFilter'] = \OCP\Config::getAppValue($this->configID, 'ldap_userlist_filter','objectClass=person');
+ $this->config['ldapGroupFilter'] = \OCP\Config::getAppValue($this->configID, 'ldap_group_filter','(objectClass=posixGroup)');
+ $this->config['ldapLoginFilter'] = \OCP\Config::getAppValue($this->configID, 'ldap_login_filter', '(uid=%uid)');
+ $this->config['ldapGroupDisplayName'] = mb_strtolower(\OCP\Config::getAppValue($this->configID, 'ldap_group_display_name', 'uid'), 'UTF-8');
+ $this->config['ldapQuotaAttribute'] = \OCP\Config::getAppValue($this->configID, 'ldap_quota_attr', '');
+ $this->config['ldapQuotaDefault'] = \OCP\Config::getAppValue($this->configID, 'ldap_quota_def', '');
+ $this->config['ldapEmailAttribute'] = \OCP\Config::getAppValue($this->configID, 'ldap_email_attr', '');
+ $this->config['ldapGroupMemberAssocAttr'] = \OCP\Config::getAppValue($this->configID, 'ldap_group_member_assoc_attribute', 'uniqueMember');
+ $this->config['ldapIgnoreNamingRules'] = \OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
+
+ $this->configured = $this->validateConfiguration();
+ }
+ }
+
+ /**
+ * @brief set LDAP configuration with values delivered by an array, not read from configuration
+ * @param $config array that holds the config parameters in an associated array
+ * @param &$setParameters optional; array where the set fields will be given to
+ * @return true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
+ */
+ public function setConfiguration($config, &$setParameters = null) {
+ if(!is_array($config)) {
+ return false;
+ }
+
+ foreach($config as $parameter => $value) {
+ if(isset($this->config[$parameter])) {
+ $this->config[$parameter] = $value;
+ if(is_array($setParameters)) {
+ $setParameters[] = $parameter;
+ }
+ }
+ }
+
+ $this->configured = $this->validateConfiguration();
+
+ return $this->configured;
+ }
+
+ /**
+ * @brief Validates the user specified configuration
+ * @returns true if configuration seems OK, false otherwise
+ */
+ private function validateConfiguration() {
+ //first step: "soft" checks: settings that are not really necessary, but advisable. If left empty, give an info message
+ if(empty($this->config['ldapBaseUsers'])) {
+ \OCP\Util::writeLog('user_ldap', 'Base tree for Users is empty, using Base DN', \OCP\Util::INFO);
+ $this->config['ldapBaseUsers'] = $this->config['ldapBase'];
+ }
+ if(empty($this->config['ldapBaseGroups'])) {
+ \OCP\Util::writeLog('user_ldap', 'Base tree for Groups is empty, using Base DN', \OCP\Util::INFO);
+ $this->config['ldapBaseGroups'] = $this->config['ldapBase'];
+ }
+ if(empty($this->config['ldapGroupFilter']) && empty($this->config['ldapGroupMemberAssocAttr'])) {
+ \OCP\Util::writeLog('user_ldap', 'No group filter is specified, LDAP group feature will not be used.', \OCP\Util::INFO);
+ }
+
+ //second step: critical checks. If left empty or filled wrong, set as unconfigured and give a warning.
+ $configurationOK = true;
+ if(empty($this->config['ldapHost'])) {
+ \OCP\Util::writeLog('user_ldap', 'No LDAP host given, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if(empty($this->config['ldapPort'])) {
+ \OCP\Util::writeLog('user_ldap', 'No LDAP Port given, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if((empty($this->config['ldapAgentName']) && !empty($this->config['ldapAgentPassword']))
+ || (!empty($this->config['ldapAgentName']) && empty($this->config['ldapAgentPassword']))) {
+ \OCP\Util::writeLog('user_ldap', 'Either no password given for the user agent or a password is given, but no LDAP agent; won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ //TODO: check if ldapAgentName is in DN form
+ if(empty($this->config['ldapBase']) && (empty($this->config['ldapBaseUsers']) && empty($this->config['ldapBaseGroups']))) {
+ \OCP\Util::writeLog('user_ldap', 'No Base DN given, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if(empty($this->config['ldapUserDisplayName'])) {
+ \OCP\Util::writeLog('user_ldap', 'No user display name attribute specified, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if(empty($this->config['ldapGroupDisplayName'])) {
+ \OCP\Util::writeLog('user_ldap', 'No group display name attribute specified, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if(empty($this->config['ldapLoginFilter'])) {
+ \OCP\Util::writeLog('user_ldap', 'No login filter specified, won`t connect.', \OCP\Util::WARN);
+ $configurationOK = false;
+ }
+ if(mb_strpos($this->config['ldapLoginFilter'], '%uid', 0, 'UTF-8') === false) {
+ \OCP\Util::writeLog('user_ldap', 'Login filter does not contain %uid place holder, won`t connect.', \OCP\Util::WARN);
+ \OCP\Util::writeLog('user_ldap', 'Login filter was ' . $this->config['ldapLoginFilter'], \OCP\Util::DEBUG);
+ $configurationOK = false;
+ }
+
+ return $configurationOK;
+ }
+
+ /**
+ * Connects and Binds to LDAP
+ */
+ private function establishConnection() {
+ static $phpLDAPinstalled = true;
+ if(!$phpLDAPinstalled) {
+ return false;
+ }
+ if(!$this->configured) {
+ \OCP\Util::writeLog('user_ldap', 'Configuration is invalid, cannot connect', \OCP\Util::WARN);
+ return false;
+ }
+ if(!$this->ldapConnectionRes) {
+ if(!function_exists('ldap_connect')) {
+ $phpLDAPinstalled = false;
+ \OCP\Util::writeLog('user_ldap', 'function ldap_connect is not available. Make sure that the PHP ldap module is installed.', \OCP\Util::ERROR);
+
+ return false;
+ }
+ $this->ldapConnectionRes = ldap_connect($this->config['ldapHost'], $this->config['ldapPort']);
+ if(ldap_set_option($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
+ if(ldap_set_option($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
+ if($this->config['ldapTLS']) {
+ ldap_start_tls($this->ldapConnectionRes);
+ }
+ }
+ }
+
+ return $this->bind();
+ }
+ }
+
+ /**
+ * Binds to LDAP
+ */
+ public function bind() {
+ $ldapLogin = @ldap_bind($this->getConnectionResource(), $this->config['ldapAgentName'], $this->config['ldapAgentPassword']);
+ if(!$ldapLogin) {
+ \OCP\Util::writeLog('user_ldap', 'Bind failed: ' . ldap_errno($this->ldapConnectionRes) . ': ' . ldap_error($this->ldapConnectionRes), \OCP\Util::ERROR);
+ $this->ldapConnectionRes = null;
+ return false;
+ }
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/apps/user_ldap/lib_ldap.php b/apps/user_ldap/lib_ldap.php
deleted file mode 100644
index 08b09304d78..00000000000
--- a/apps/user_ldap/lib_ldap.php
+++ /dev/null
@@ -1,721 +0,0 @@
-<?php
-
-/**
- * ownCloud – LDAP lib
- *
- * @author Arthur Schiwon
- * @copyright 2012 Arthur Schiwon blizzz@owncloud.com
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-define('LDAP_GROUP_MEMBER_ASSOC_ATTR','uniqueMember');
-define('LDAP_GROUP_DISPLAY_NAME_ATTR','cn');
-
-//needed to unbind, because we use OC_LDAP only statically
-class OC_LDAP_DESTRUCTOR {
- public function __destruct() {
- OC_LDAP::destruct();
- }
-}
-
-class OC_LDAP {
- static protected $ldapConnectionRes = false;
- static protected $configured = false;
-
- //cached settings
- static protected $ldapHost;
- static protected $ldapPort;
- static protected $ldapBase;
- static protected $ldapBaseUsers;
- static protected $ldapBaseGroups;
- static protected $ldapAgentName;
- static protected $ldapAgentPassword;
- static protected $ldapTLS;
- static protected $ldapNoCase;
- static protected $ldapIgnoreNamingRules;
- // user and group settings, that are needed in both backends
- static protected $ldapUserDisplayName;
- static protected $ldapUserFilter;
- static protected $ldapGroupDisplayName;
- static protected $ldapLoginFilter;
-
- static protected $__d;
-
- /**
- * @brief initializes the LDAP backend
- * @param $force read the config settings no matter what
- *
- * initializes the LDAP backend
- */
- static public function init($force = false) {
- if(is_null(self::$__d)) {
- self::$__d = new OC_LDAP_DESTRUCTOR();
- }
- self::readConfiguration($force);
- self::establishConnection();
- }
-
- static public function destruct() {
- @ldap_unbind(self::$ldapConnectionRes);
- }
-
- /**
- * @brief returns a read-only configuration value
- * @param $key the name of the configuration value
- * @returns the value on success, otherwise null
- *
- * returns a read-only configuration values
- *
- * we cannot work with getters, because it is a static class
- */
- static public function conf($key) {
- if(!self::$configured) {
- self::init();
- }
-
- $availableProperties = array(
- 'ldapUserDisplayName',
- 'ldapGroupDisplayName',
- 'ldapLoginFilter'
- );
-
- if(in_array($key, $availableProperties)) {
- return self::$$key;
- }
-
- return null;
- }
-
- /**
- * gives back the database table for the query
- */
- static private function getMapTable($isUser) {
- if($isUser) {
- return '*PREFIX*ldap_user_mapping';
- } else {
- return '*PREFIX*ldap_group_mapping';
- }
- }
-
- /**
- * @brief returns the LDAP DN for the given internal ownCloud name of the group
- * @param $name the ownCloud name in question
- * @returns string with the LDAP DN on success, otherwise false
- *
- * returns the LDAP DN for the given internal ownCloud name of the group
- */
- static public function groupname2dn($name) {
- return self::ocname2dn($name, false);
- }
-
- /**
- * @brief returns the LDAP DN for the given internal ownCloud name of the user
- * @param $name the ownCloud name in question
- * @returns string with the LDAP DN on success, otherwise false
- *
- * returns the LDAP DN for the given internal ownCloud name of the user
- */
- static public function username2dn($name) {
- $dn = self::ocname2dn($name, true);
- if($dn) {
- return $dn;
- } else {
- //fallback: user is not mapped
- self::init();
- $filter = self::combineFilterWithAnd(array(
- self::$ldapUserFilter,
- self::$ldapUserDisplayName . '=' . $name,
- ));
- $result = self::searchUsers($filter, 'dn');
- if(isset($result[0]['dn'])) {
- self::mapUser($result[0], $name);
- return $result[0];
- }
- }
-
- return false;
- }
-
- static private function ocname2dn($name, $isUser) {
- $table = self::getMapTable($isUser);
-
- $query = OCP\DB::prepare('
- SELECT ldap_dn
- FROM '.$table.'
- WHERE owncloud_name = ?
- ');
-
- $record = $query->execute(array($name))->fetchOne();
- return $record;
- }
-
- /**
- * @brief returns the internal ownCloud name for the given LDAP DN of the group
- * @param $dn the dn of the group object
- * @param $ldapname optional, the display name of the object
- * @returns string with with the name to use in ownCloud, false on DN outside of search DN
- *
- * returns the internal ownCloud name for the given LDAP DN of the group
- */
- static public function dn2groupname($dn, $ldapname = null) {
- if(mb_strripos($dn, self::$ldapBaseGroups, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen(self::$ldapBaseGroups, 'UTF-8'))) {
- return false;
- }
- return self::dn2ocname($dn, $ldapname, false);
- }
-
- /**
- * @brief returns the internal ownCloud name for the given LDAP DN of the user
- * @param $dn the dn of the user object
- * @param $ldapname optional, the display name of the object
- * @returns string with with the name to use in ownCloud
- *
- * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN
- */
- static public function dn2username($dn, $ldapname = null) {
- if(mb_strripos($dn, self::$ldapBaseUsers, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen(self::$ldapBaseUsers, 'UTF-8'))) {
- return false;
- }
- return self::dn2ocname($dn, $ldapname, true);
- }
-
- static public function dn2ocname($dn, $ldapname = null, $isUser = true) {
- $dn = self::sanitizeDN($dn);
- $table = self::getMapTable($isUser);
- if($isUser) {
- $nameAttribute = self::conf('ldapUserDisplayName');
- } else {
- $nameAttribute = self::conf('ldapGroupDisplayName');
- }
-
- $query = OCP\DB::prepare('
- SELECT owncloud_name
- FROM '.$table.'
- WHERE ldap_dn = ?
- ');
-
- $component = $query->execute(array($dn))->fetchOne();
- if($component) {
- return $component;
- }
-
- if(is_null($ldapname)) {
- $ldapname = self::readAttribute($dn, $nameAttribute);
- $ldapname = $ldapname[0];
- }
- $ldapname = self::sanitizeUsername($ldapname);
-
- //a new user/group! Then let's try to add it. We're shooting into the blue with the user/group name, assuming that in most cases there will not be a conflict. Otherwise an error will occur and we will continue with our second shot.
- if(self::mapComponent($dn, $ldapname, $isUser)) {
- return $ldapname;
- }
-
- //doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located.
- $oc_name = self::alternateOwnCloudName($ldapname, $dn);
- if(self::mapComponent($dn, $oc_name, $isUser)) {
- return $oc_name;
- }
-
- //and this of course should never been thrown :)
- throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.');
- }
-
- /**
- * @brief gives back the user names as they are used ownClod internally
- * @param $ldapGroups an array with the ldap Users result in style of array ( array ('dn' => foo, 'uid' => bar), ... )
- * @returns an array with the user names to use in ownCloud
- *
- * gives back the user names as they are used ownClod internally
- */
- static public function ownCloudUserNames($ldapUsers) {
- return self::ldap2ownCloudNames($ldapUsers, true);
- }
-
- /**
- * @brief gives back the group names as they are used ownClod internally
- * @param $ldapGroups an array with the ldap Groups result in style of array ( array ('dn' => foo, 'cn' => bar), ... )
- * @returns an array with the group names to use in ownCloud
- *
- * gives back the group names as they are used ownClod internally
- */
- static public function ownCloudGroupNames($ldapGroups) {
- return self::ldap2ownCloudNames($ldapGroups, false);
- }
-
- static private function ldap2ownCloudNames($ldapObjects, $isUsers) {
- if($isUsers) {
- $knownObjects = self::mappedUsers();
- $nameAttribute = self::conf('ldapUserDisplayName');
- } else {
- $knownObjects = self::mappedGroups();
- $nameAttribute = self::conf('ldapGroupDisplayName');
- }
- $ownCloudNames = array();
-
- foreach($ldapObjects as $ldapObject) {
- $key = self::recursiveArraySearch($knownObjects, $ldapObject['dn']);
-
- //everything is fine when we know the group
- if($key !== false) {
- $ownCloudNames[] = $knownObjects[$key]['owncloud_name'];
- continue;
- }
-
- //a new group! Then let's try to add it. We're shooting into the blue with the group name, assuming that in most cases there will not be a conflict. But first make sure, that the display name contains only allowed characters.
- $ocname = self::sanitizeUsername($ldapObject[$nameAttribute]);
- if(self::mapComponent($ldapObject['dn'], $ocname, $isUsers)) {
- $ownCloudNames[] = $ocname;
- continue;
- }
-
- //doh! There is a conflict. We need to distinguish between groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this entry is located.
- $ocname = self::alternateOwnCloudName($ocname, $ldapObject['dn']);
- if(self::mapComponent($ldapObject['dn'], $ocname, $isUsers)) {
- $ownCloudNames[] = $ocname;
- continue;
- }
-
- //and this of course should never been thrown :)
- throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.');
- }
- return $ownCloudNames;
- }
-
- /**
- * @brief creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
- * @param $name the display name of the object
- * @param $dn the dn of the object
- * @returns string with with the name to use in ownCloud
- *
- * creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
- */
- static private function alternateOwnCloudName($name, $dn) {
- $ufn = ldap_dn2ufn($dn);
- $name = $name . '@' . trim(OCP\Util::mb_substr_replace($ufn, '', 0, mb_strpos($ufn, ',', 0, 'UTF-8'), 'UTF-8'));
- $name = self::sanitizeUsername($name);
- return $name;
- }
-
- /**
- * @brief retrieves all known groups from the mappings table
- * @returns array with the results
- *
- * retrieves all known groups from the mappings table
- */
- static private function mappedGroups() {
- return self::mappedComponents(false);
- }
-
- /**
- * @brief retrieves all known users from the mappings table
- * @returns array with the results
- *
- * retrieves all known users from the mappings table
- */
- static private function mappedUsers() {
- return self::mappedComponents(true);
- }
-
- static private function mappedComponents($isUsers) {
- $table = self::getMapTable($isUsers);
-
- $query = OCP\DB::prepare('
- SELECT ldap_dn, owncloud_name
- FROM '. $table
- );
-
- return $query->execute()->fetchAll();
- }
-
- /**
- * @brief inserts a new user or group into the mappings table
- * @param $dn the record in question
- * @param $ocname the name to use in ownCloud
- * @param $isUser is it a user or a group?
- * @returns true on success, false otherwise
- *
- * inserts a new user or group into the mappings table
- */
- static private function mapComponent($dn, $ocname, $isUser = true) {
- $table = self::getMapTable($isUser);
- $dn = self::sanitizeDN($dn);
-
- $sqlAdjustment = '';
- $dbtype = OCP\Config::getSystemValue('dbtype');
- if($dbtype == 'mysql') {
- $sqlAdjustment = 'FROM dual';
- }
-
- $insert = OCP\DB::prepare('
- INSERT INTO '.$table.' (ldap_dn, owncloud_name)
- SELECT ?,?
- '.$sqlAdjustment.'
- WHERE NOT EXISTS (
- SELECT 1
- FROM '.$table.'
- WHERE ldap_dn = ?
- OR owncloud_name = ? )
- ');
-
- $res = $insert->execute(array($dn, $ocname, $dn, $ocname));
-
- if(OCP\DB::isError($res)) {
- return false;
- }
-
- $insRows = $res->numRows();
-
- if($insRows == 0) {
- return false;
- }
-
- return true;
- }
-
- static public function fetchListOfUsers($filter, $attr) {
- return self::fetchList(OC_LDAP::searchUsers($filter, $attr), (count($attr) > 1));
- }
-
- static public function fetchListOfGroups($filter, $attr) {
- return self::fetchList(OC_LDAP::searchGroups($filter, $attr), (count($attr) > 1));
- }
-
- static private function fetchList($list, $manyAttributes) {
- if(is_array($list)) {
- if($manyAttributes) {
- return $list;
- } else {
- return array_unique($list, SORT_LOCALE_STRING);
- }
- }
-
- //error cause actually, maybe throw an exception in future.
- return array();
- }
-
- /**
- * @brief reads a given attribute for an LDAP record identified by a DN
- * @param $dn the record in question
- * @param $attr the attribute that shall be retrieved
- * @returns the values in an array on success, false otherwise
- *
- * Reads an attribute from an LDAP entry
- */
- static public function readAttribute($dn, $attr) {
- $cr = self::getConnectionResource();
- $rr = ldap_read($cr, $dn, 'objectClass=*', array($attr));
- $er = ldap_first_entry($cr, $rr);
- //LDAP attributes are not case sensitive
- $result = OCP\Util::mb_array_change_key_case(ldap_get_attributes($cr, $er), MB_CASE_LOWER, 'UTF-8');
- $attr = mb_strtolower($attr, 'UTF-8');
-
- if(isset($result[$attr]) && $result[$attr]['count'] > 0){
- $values = array();
- for($i=0;$i<$result[$attr]['count'];$i++) {
- $values[] = self::resemblesDN($attr) ? self::sanitizeDN($result[$attr][$i]) : $result[$attr][$i];
- }
- return $values;
- }
- return false;
- }
-
- /**
- * @brief executes an LDAP search, optimized for Users
- * @param $filter the LDAP filter for the search
- * @param $attr optional, when a certain attribute shall be filtered out
- * @returns array with the search result
- *
- * Executes an LDAP search
- */
- static public function searchUsers($filter, $attr = null) {
- self::init();
- return self::search($filter, self::$ldapBaseUsers, $attr);
- }
-
- /**
- * @brief executes an LDAP search, optimized for Groups
- * @param $filter the LDAP filter for the search
- * @param $attr optional, when a certain attribute shall be filtered out
- * @returns array with the search result
- *
- * Executes an LDAP search
- */
- static public function searchGroups($filter, $attr = null) {
- self::init();
- return self::search($filter, self::$ldapBaseGroups, $attr);
- }
-
- /**
- * @brief executes an LDAP search
- * @param $filter the LDAP filter for the search
- * @param $base the LDAP subtree that shall be searched
- * @param $attr optional, when a certain attribute shall be filtered out
- * @returns array with the search result
- *
- * Executes an LDAP search
- */
- static private function search($filter, $base, $attr = null) {
- if(!is_null($attr) && !is_array($attr)) {
- $attr = array(mb_strtolower($attr, 'UTF-8'));
- }
-
- // See if we have a resource
- $link_resource = self::getConnectionResource();
- if(is_resource($link_resource)) {
- $sr = ldap_search($link_resource, $base, $filter, $attr);
- $findings = ldap_get_entries($link_resource, $sr );
-
- // if we're here, probably no connection resource is returned.
- // to make ownCloud behave nicely, we simply give back an empty array.
- if(is_null($findings)) {
- return array();
- }
- } else {
- // Seems like we didn't find any resource.
- // Return an empty array just like before.
- return array();
- }
-
- if(!is_null($attr)) {
- $selection = array();
- $multiarray = false;
- if(count($attr) > 1) {
- $multiarray = true;
- $i = 0;
- }
- foreach($findings as $item) {
- if(!is_array($item)) {
- continue;
- }
- $item = OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8');
-
- if($multiarray) {
- foreach($attr as $key) {
- $key = mb_strtolower($key, 'UTF-8');
- if(isset($item[$key])) {
- if($key != 'dn'){
- $selection[$i][$key] = self::resemblesDN($key) ? self::sanitizeDN($item[$key][0]) : $item[$key][0];
- } else {
- $selection[$i][$key] = self::sanitizeDN($item[$key]);
- }
- }
-
- }
- $i++;
- } else {
- //tribute to case insensitivity
- $key = mb_strtolower($attr[0], 'UTF-8');
-
- if(isset($item[$key])) {
- if(self::resemblesDN($key)) {
- $selection[] = self::sanitizeDN($item[$key]);
- } else {
- $selection[] = $item[$key];
- }
- }
- }
-
- }
- return $selection;
- }
-
- return $findings;
- }
-
- static private function resemblesDN($attr) {
- $resemblingAttributes = array(
- 'dn',
- 'uniquemember',
- 'member'
- );
- return in_array($attr, $resemblingAttributes);
- }
-
- static private function sanitizeDN($dn) {
- //OID sometimes gives back DNs with whitespace after the comma a la "uid=foo, cn=bar, dn=..." We need to tackle this!
- $dn = preg_replace('/([^\\\]),(\s+)/u','\1,',$dn);
-
- //make comparisons and everything work
- $dn = mb_strtolower($dn, 'UTF-8');
-
- return $dn;
- }
-
- static private function sanitizeUsername($name) {
- if(self::$ldapIgnoreNamingRules) {
- return $name;
- }
-
- //REPLACEMENTS
- $name = OCP\Util::mb_str_replace(' ', '_', $name, 'UTF-8');
-
- //every remaining unallowed characters will be removed
- $name = preg_replace('/[^a-zA-Z0-9_.@-]/u', '', $name);
-
- return $name;
- }
-
- /**
- * @brief combines the input filters with AND
- * @param $filters array, the filters to connect
- * @returns the combined filter
- *
- * Combines Filter arguments with AND
- */
- static public function combineFilterWithAnd($filters) {
- return self::combineFilter($filters,'&');
- }
-
- /**
- * @brief combines the input filters with AND
- * @param $filters array, the filters to connect
- * @returns the combined filter
- *
- * Combines Filter arguments with AND
- */
- static public function combineFilterWithOr($filters) {
- return self::combineFilter($filters,'|');
- }
-
- /**
- * @brief combines the input filters with given operator
- * @param $filters array, the filters to connect
- * @param $operator either & or |
- * @returns the combined filter
- *
- * Combines Filter arguments with AND
- */
- static private function combineFilter($filters, $operator) {
- $combinedFilter = '('.$operator;
- foreach($filters as $filter) {
- if($filter[0] != '(') {
- $filter = '('.$filter.')';
- }
- $combinedFilter.=$filter;
- }
- $combinedFilter.=')';
- return $combinedFilter;
- }
-
- /**
- * Returns the LDAP handler
- */
- static private function getConnectionResource() {
- if(!self::$ldapConnectionRes) {
- self::init();
- }
- if(is_null(self::$ldapConnectionRes)) {
- OCP\Util::writeLog('ldap', 'Connection could not be established', OCP\Util::INFO);
- }
- return self::$ldapConnectionRes;
- }
-
- /**
- * Caches the general LDAP configuration.
- */
- static private function readConfiguration($force = false) {
- if(!self::$configured || $force) {
- self::$ldapHost = OCP\Config::getAppValue('user_ldap', 'ldap_host', '');
- self::$ldapPort = OCP\Config::getAppValue('user_ldap', 'ldap_port', 389);
- self::$ldapAgentName = OCP\Config::getAppValue('user_ldap', 'ldap_dn','');
- self::$ldapAgentPassword = base64_decode(OCP\Config::getAppValue('user_ldap', 'ldap_agent_password',''));
- self::$ldapBase = OCP\Config::getAppValue('user_ldap', 'ldap_base', '');
- self::$ldapBaseUsers = OCP\Config::getAppValue('user_ldap', 'ldap_base_users',self::$ldapBase);
- self::$ldapBaseGroups = OCP\Config::getAppValue('user_ldap', 'ldap_base_groups', self::$ldapBase);
- self::$ldapTLS = OCP\Config::getAppValue('user_ldap', 'ldap_tls',0);
- self::$ldapNoCase = OCP\Config::getAppValue('user_ldap', 'ldap_nocase', 0);
- self::$ldapUserDisplayName = mb_strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_display_name', 'uid'), 'UTF-8');
- self::$ldapUserFilter = OCP\Config::getAppValue('user_ldap', 'ldap_userlist_filter','objectClass=person');
- self::$ldapLoginFilter = OCP\Config::getAppValue('user_ldap', 'ldap_login_filter', '(uid=%uid)');
- self::$ldapGroupDisplayName = mb_strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_group_display_name', LDAP_GROUP_DISPLAY_NAME_ATTR), 'UTF-8');
- self::$ldapIgnoreNamingRules = OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
-
- if(empty(self::$ldapBaseUsers)) {
- OCP\Util::writeLog('ldap', 'Base for Users is empty, using Base DN', OCP\Util::INFO);
- self::$ldapBaseUsers = self::$ldapBase;
- }
- if(empty(self::$ldapBaseGroups)) {
- OCP\Util::writeLog('ldap', 'Base for Groups is empty, using Base DN', OCP\Util::INFO);
- self::$ldapBaseGroups = self::$ldapBase;
- }
-
- if(
- !empty(self::$ldapHost)
- && !empty(self::$ldapPort)
- && (
- (!empty(self::$ldapAgentName) && !empty(self::$ldapAgentPassword))
- || ( empty(self::$ldapAgentName) && empty(self::$ldapAgentPassword))
- )
- && !empty(self::$ldapBase)
- && !empty(self::$ldapUserDisplayName)
- )
- {
- self::$configured = true;
- }
- }
- }
-
- /**
- * Connects and Binds to LDAP
- */
- static private function establishConnection() {
- if(!self::$configured) {
- OCP\Util::writeLog('ldap', 'Configuration is invalid, cannot connect', OCP\Util::INFO);
- return false;
- }
- if(!self::$ldapConnectionRes) {
- self::$ldapConnectionRes = ldap_connect(self::$ldapHost, self::$ldapPort);
- if(ldap_set_option(self::$ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
- if(ldap_set_option(self::$ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
- if(self::$ldapTLS) {
- ldap_start_tls(self::$ldapConnectionRes);
- }
- }
- }
-
- $ldapLogin = @ldap_bind(self::$ldapConnectionRes, self::$ldapAgentName, self::$ldapAgentPassword );
- if(!$ldapLogin) {
- OCP\Util::writeLog('ldap', 'Bind failed: ' . ldap_errno(self::$ldapConnectionRes) . ': ' . ldap_error(self::$ldapConnectionRes), OCP\Util::ERROR);
- self::$ldapConnectionRes = null;
- return false;
- }
- }
- }
-
- static public function areCredentialsValid($name, $password) {
- return @ldap_bind(self::getConnectionResource(), $name, $password);
- }
-
- /**
- * taken from http://www.php.net/manual/en/function.array-search.php#97645
- * TODO: move somewhere, where its better placed since it is not LDAP specific. OC_Helper maybe?
- */
- static public function recursiveArraySearch($haystack, $needle, $index = null) {
- $aIt = new RecursiveArrayIterator($haystack);
- $it = new RecursiveIteratorIterator($aIt);
-
- while($it->valid()) {
- if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) {
- return $aIt->key();
- }
-
- $it->next();
- }
-
- return false;
- }
-
- }
diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php
index 2be6b46fb23..106459580fa 100644
--- a/apps/user_ldap/tests/group_ldap.php
+++ b/apps/user_ldap/tests/group_ldap.php
@@ -26,8 +26,8 @@ class Test_Group_Ldap extends UnitTestCase {
}
function testSingleBackend(){
- OC_Group::useBackend(new OC_GROUP_LDAP());
- $group_ldap = new OC_GROUP_LDAP();
+ OC_Group::useBackend(new OCA\user_ldap\GROUP_LDAP());
+ $group_ldap = new OCA\user_ldap\GROUP_LDAP();
$this->assertIsA(OC_Group::getGroups(),gettype(array()));
$this->assertIsA($group_ldap->getGroups(),gettype(array()));
diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php
index b51d9a55cc7..a4a8921d08d 100644
--- a/apps/user_ldap/user_ldap.php
+++ b/apps/user_ldap/user_ldap.php
@@ -23,13 +23,9 @@
*
*/
-class OC_USER_LDAP extends OC_User_Backend {
+namespace OCA\user_ldap;
- // cached settings
- protected $ldapUserFilter;
- protected $ldapQuotaAttribute;
- protected $ldapQuotaDefault;
- protected $ldapEmailAttribute;
+class USER_LDAP extends lib\Access implements \OCP\UserInterface {
// will be retrieved from LDAP server
protected $ldap_dc = false;
@@ -37,39 +33,32 @@ class OC_USER_LDAP extends OC_User_Backend {
// cache getUsers()
protected $_users = null;
- public function __construct() {
- $this->ldapUserFilter = OCP\Config::getAppValue('user_ldap', 'ldap_userlist_filter', '(objectClass=posixAccount)');
- $this->ldapQuotaAttribute = OCP\Config::getAppValue('user_ldap', 'ldap_quota_attr', '');
- $this->ldapQuotaDefault = OCP\Config::getAppValue('user_ldap', 'ldap_quota_def', '');
- $this->ldapEmailAttribute = OCP\Config::getAppValue('user_ldap', 'ldap_email_attr', '');
- }
-
private function updateQuota($dn) {
$quota = null;
- if(!empty($this->ldapQuotaDefault)) {
- $quota = $this->ldapQuotaDefault;
+ if(!empty($this->connection->ldapQuotaDefault)) {
+ $quota = $this->connection->ldapQuotaDefault;
}
- if(!empty($this->ldapQuotaAttribute)) {
- $aQuota = OC_LDAP::readAttribute($dn, $this->ldapQuotaAttribute);
+ if(!empty($this->connection->ldapQuotaAttribute)) {
+ $aQuota = $this->readAttribute($dn, $this->connection->ldapQuotaAttribute);
if($aQuota && (count($aQuota) > 0)) {
$quota = $aQuota[0];
}
}
if(!is_null($quota)) {
- OCP\Config::setUserValue(OC_LDAP::dn2username($dn), 'files', 'quota', OCP\Util::computerFileSize($quota));
+ \OCP\Config::setUserValue($this->dn2username($dn), 'files', 'quota', \OCP\Util::computerFileSize($quota));
}
}
private function updateEmail($dn) {
$email = null;
- if(!empty($this->ldapEmailAttribute)) {
- $aEmail = OC_LDAP::readAttribute($dn, $this->ldapEmailAttribute);
+ if(!empty($this->connection->ldapEmailAttribute)) {
+ $aEmail = $this->readAttribute($dn, $this->connection->ldapEmailAttribute);
if($aEmail && (count($aEmail) > 0)) {
$email = $aEmail[0];
}
- if(!is_null($email)){
- OCP\Config::setUserValue(OC_LDAP::dn2username($dn), 'settings', 'email', $email);
+ if(!is_null($email)) {
+ \OCP\Config::setUserValue($this->dn2username($dn), 'settings', 'email', $email);
}
}
}
@@ -84,15 +73,15 @@ class OC_USER_LDAP extends OC_User_Backend {
*/
public function checkPassword($uid, $password){
//find out dn of the user name
- $filter = OCP\Util::mb_str_replace('%uid', $uid, OC_LDAP::conf('ldapLoginFilter'), 'UTF-8');
- $ldap_users = OC_LDAP::fetchListOfUsers($filter, 'dn');
+ $filter = \OCP\Util::mb_str_replace('%uid', $uid, $this->connection->ldapLoginFilter, 'UTF-8');
+ $ldap_users = $this->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
return false;
}
$dn = $ldap_users[0];
//are the credentials OK?
- if(!OC_LDAP::areCredentialsValid($dn, $password)) {
+ if(!$this->areCredentialsValid($dn, $password)) {
return false;
}
@@ -101,7 +90,7 @@ class OC_USER_LDAP extends OC_User_Backend {
$this->updateEmail($dn);
//give back the display name
- return OC_LDAP::dn2username($dn);
+ return $this->dn2username($dn);
}
/**
@@ -112,8 +101,8 @@ class OC_USER_LDAP extends OC_User_Backend {
*/
public function getUsers(){
if(is_null($this->_users)) {
- $ldap_users = OC_LDAP::fetchListOfUsers($this->ldapUserFilter, array(OC_LDAP::conf('ldapUserDisplayName'), 'dn'));
- $this->_users = OC_LDAP::ownCloudUserNames($ldap_users);
+ $ldap_users = $this->fetchListOfUsers($this->connection->ldapUserFilter, array($this->connection->ldapUserDisplayName, 'dn'));
+ $this->_users = $this->ownCloudUserNames($ldap_users);
}
return $this->_users;
}
@@ -125,13 +114,13 @@ class OC_USER_LDAP extends OC_User_Backend {
*/
public function userExists($uid){
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
- $dn = OC_LDAP::username2dn($uid);
+ $dn = $this->username2dn($uid);
if(!$dn) {
return false;
}
//if user really still exists, we will be able to read his cn
- $cn = OC_LDAP::readAttribute($dn, 'cn');
+ $cn = $this->readAttribute($dn, 'cn');
if(!$cn || empty($cn)) {
return false;
}
@@ -139,4 +128,27 @@ class OC_USER_LDAP extends OC_User_Backend {
return true;
}
+ /**
+ * @brief delete a user
+ * @param $uid The username of the user to delete
+ * @returns true/false
+ *
+ * Deletes a user
+ */
+ public function deleteUser($uid) {
+ return false;
+ }
+
+ /**
+ * @brief Check if backend implements actions
+ * @param $actions bitwise-or'ed actions
+ * @returns boolean
+ *
+ * Returns the supported actions as int to be
+ * compared with OC_USER_BACKEND_CREATE_USER etc.
+ */
+ public function implementsActions($actions) {
+ return (bool)(OC_USER_BACKEND_CHECK_PASSWORD & $actions);
+ }
+
} \ No newline at end of file
diff --git a/apps/user_migrate/templates/settings.php b/apps/user_migrate/templates/settings.php
index 1718abe9e0f..bce5fb2d7ca 100644
--- a/apps/user_migrate/templates/settings.php
+++ b/apps/user_migrate/templates/settings.php
@@ -12,7 +12,7 @@
<?php } ?>
<legend><strong><?php echo $l->t('Import user account');?></strong></legend>
</p>
- <p><input type="file" id="owncloud_import" name="owncloud_import" style="width:180px;"><label for="owncloud_import"> <?php echo $l->t('ownCloud User Zip');?></label>
+ <p><input type="file" id="owncloud_import" name="owncloud_import" style="width:280px;"><label for="owncloud_import"> <?php echo $l->t('ownCloud User Zip');?></label>
</p>
<input type="submit" name="user_import" value="<?php echo $l->t('Import'); ?>" />
</fieldset>
diff --git a/apps/user_openid/class.openid.v3.php b/apps/user_openid/class.openid.v3.php
deleted file mode 100644
index eeb31986659..00000000000
--- a/apps/user_openid/class.openid.v3.php
+++ /dev/null
@@ -1,326 +0,0 @@
-<?php
-/*
- FREE TO USE
- Under License: GPLv3
- Simple OpenID PHP Class
-
- Some modifications by Eddie Roosenmaallen, eddie@roosenmaallen.com
-
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-This Class was written to make easy for you to integrate OpenID on your website.
-This is just a client, which checks for user's identity. This Class Requires CURL Module.
-It should be easy to use some other HTTP Request Method, but remember, often OpenID servers
-are using SSL.
-We need to be able to perform SSL Verification on the background to check for valid signature.
-
-HOW TO USE THIS CLASS:
- STEP 1)
- $openid = new SimpleOpenID;
- :: SET IDENTITY ::
- $openid->SetIdentity($_POST['openid_url']);
- :: SET RETURN URL ::
- $openid->SetApprovedURL('http://www.yoursite.com/return.php'); // Script which handles a response from OpenID Server
- :: SET TRUST ROOT ::
- $openid->SetTrustRoot('http://www.yoursite.com/');
- :: FETCH SERVER URL FROM IDENTITY PAGE :: [Note: It is recomended to cache this (Session, Cookie, Database)]
- $openid->GetOpenIDServer(); // Returns false if server is not found
- :: REDIRECT USER TO OPEN ID SERVER FOR APPROVAL ::
-
- :: (OPTIONAL) SET OPENID SERVER ::
- $openid->SetOpenIDServer($server_url); // If you have cached previously this, you don't have to call GetOpenIDServer and set value this directly
-
- STEP 2)
- Once user gets returned we must validate signature
- :: VALIDATE REQUEST ::
- true|false = $openid->ValidateWithServer();
-
- ERRORS:
- array = $openid->GetError(); // Get latest Error code
-
- FIELDS:
- OpenID allowes you to retreive a profile. To set what fields you'd like to get use (accepts either string or array):
- $openid->SetRequiredFields(array('email','fullname','dob','gender','postcode','country','language','timezone'));
- or
- $openid->SetOptionalFields('postcode');
-
-IMPORTANT TIPS:
-OPENID as is now, is not trust system. It is a great single-sign on method. If you want to
-store information about OpenID in your database for later use, make sure you handle url identities
-properly.
- For example:
- https://steve.myopenid.com/
- https://steve.myopenid.com
- http://steve.myopenid.com/
- http://steve.myopenid.com
- ... are representing one single user. Some OpenIDs can be in format openidserver.com/users/user/ - keep this in mind when storing identities
-
- To help you store an OpenID in your DB, you can use function:
- $openid_db_safe = $openid->OpenID_Standarize($upenid);
- This may not be comatible with current specs, but it works in current enviroment. Use this function to get openid
- in one format like steve.myopenid.com (without trailing slashes and http/https).
- Use output to insert Identity to database. Don't use this for validation - it may fail.
-
-*/
-
-class SimpleOpenID{
- var $openid_url_identity;
- var $URLs = array();
- var $error = array();
- var $fields = array(
- 'required' => array(),
- 'optional' => array(),
- );
-
- function SimpleOpenID(){
- if (!function_exists('curl_exec')) {
- die('Error: Class SimpleOpenID requires curl extension to work');
- }
- }
- function SetOpenIDServer($a){
- $this->URLs['openid_server'] = $a;
- }
- function SetTrustRoot($a){
- $this->URLs['trust_root'] = $a;
- }
- function SetCancelURL($a){
- $this->URLs['cancel'] = $a;
- }
- function SetApprovedURL($a){
- $this->URLs['approved'] = $a;
- }
- function SetRequiredFields($a){
- if (is_array($a)){
- $this->fields['required'] = $a;
- }else{
- $this->fields['required'][] = $a;
- }
- }
- function SetOptionalFields($a){
- if (is_array($a)){
- $this->fields['optional'] = $a;
- }else{
- $this->fields['optional'][] = $a;
- }
- }
- function SetIdentity($a){ // Set Identity URL
- if ((stripos($a, 'http://') === false)
- && (stripos($a, 'https://') === false)){
- $a = 'http://'.$a;
- }
-/*
- $u = parse_url(trim($a));
- if (!isset($u['path'])){
- $u['path'] = '/';
- }else if(substr($u['path'],-1,1) == '/'){
- $u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
- }
- if (isset($u['query'])){ // If there is a query string, then use identity as is
- $identity = $a;
- }else{
- $identity = $u['scheme'] . '://' . $u['host'] . $u['path'];
- }
-//*/
- $this->openid_url_identity = $a;
- }
- function GetIdentity(){ // Get Identity
- return $this->openid_url_identity;
- }
- function GetError(){
- $e = $this->error;
- return array('code'=>$e[0],'description'=>$e[1]);
- }
-
- function ErrorStore($code, $desc = null){
- $errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
- if ($desc == null){
- $desc = $errs[$code];
- }
- $this->error = array($code,$desc);
- }
-
- function IsError(){
- if (count($this->error) > 0){
- return true;
- }else{
- return false;
- }
- }
-
- function splitResponse($response) {
- $r = array();
- $response = explode("\n", $response);
- foreach($response as $line) {
- $line = trim($line);
- if ($line != "") {
- list($key, $value) = explode(":", $line, 2);
- $r[trim($key)] = trim($value);
- }
- }
- return $r;
- }
-
- function OpenID_Standarize($openid_identity = null){
- if ($openid_identity === null)
- $openid_identity = $this->openid_url_identity;
-
- $u = parse_url(strtolower(trim($openid_identity)));
-
- if (!isset($u['path']) || ($u['path'] == '/')) {
- $u['path'] = '';
- }
- if(substr($u['path'],-1,1) == '/'){
- $u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
- }
- if (isset($u['query'])){ // If there is a query string, then use identity as is
- return $u['host'] . $u['path'] . '?' . $u['query'];
- }else{
- return $u['host'] . $u['path'];
- }
- }
-
- function array2url($arr){ // converts associated array to URL Query String
- if (!is_array($arr)){
- return false;
- }
- $query = '';
- foreach($arr as $key => $value){
- $query .= $key . "=" . $value . "&";
- }
- return $query;
- }
- function FSOCK_Request($url, $method="GET", $params = ""){
- $fp = fsockopen("ssl://www.myopenid.com", 443, $errno, $errstr, 3); // Connection timeout is 3 seconds
- if (!$fp) {
- $this->ErrorStore('OPENID_SOCKETERROR', $errstr);
- return false;
- } else {
- $request = $method . " /server HTTP/1.0\r\n";
- $request .= "User-Agent: Simple OpenID PHP Class (http://www.phpclasses.org/simple_openid)\r\n";
- $request .= "Connection: close\r\n\r\n";
- fwrite($fp, $request);
- stream_set_timeout($fp, 4); // Connection response timeout is 4 seconds
- $res = fread($fp, 2000);
- $info = stream_get_meta_data($fp);
- fclose($fp);
-
- if ($info['timed_out']) {
- $this->ErrorStore('OPENID_SOCKETTIMEOUT');
- } else {
- return $res;
- }
- }
- }
- function CURL_Request($url, $method="GET", $params = "") { // Remember, SSL MUST BE SUPPORTED
- if (is_array($params)) $params = $this->array2url($params);
- $curl = curl_init($url . ($method == "GET" && $params != "" ? "?" . $params : ""));
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($curl, CURLOPT_HEADER, false);
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
- curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
- if ($method == "POST") curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- $response = curl_exec($curl);
-
- if (curl_errno($curl) == 0){
- $response;
- }else{
- $this->ErrorStore('OPENID_CURL', curl_error($curl));
- }
- return $response;
- }
-
- function HTML2OpenIDServer($content) {
- $get = array();
-
- // Get details of their OpenID server and (optional) delegate
- preg_match_all('/<link[^>]*rel=[\'"](openid2.provider )?openid.server[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
- preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"](openid2.provider )?openid.server[\'"][^>]*\/?>/i', $content, $matches2);
- $servers = array_merge($matches1[2], $matches2[1]);
-
- preg_match_all('/<link[^>]*rel=[\'"]openid.delegate[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
-
- preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid.delegate[\'"][^>]*\/?>/i', $content, $matches2);
-
- $delegates = array_merge($matches1[1], $matches2[1]);
-
- $ret = array($servers, $delegates);
- return $ret;
- }
-
- function GetOpenIDServer(){
- $response = $this->CURL_Request($this->openid_url_identity);
- list($servers, $delegates) = $this->HTML2OpenIDServer($response);
- if (count($servers) == 0){
- $this->ErrorStore('OPENID_NOSERVERSFOUND');
- return false;
- }
- if (isset($delegates[0])
- && ($delegates[0] != "")){
- $this->SetIdentity($delegates[0]);
- }
- $this->SetOpenIDServer($servers[0]);
- return $servers[0];
- }
-
- function GetRedirectURL(){
- $params = array();
- $params['openid.return_to'] = urlencode($this->URLs['approved']);
- $params['openid.mode'] = 'checkid_setup';
- $params['openid.identity'] = urlencode($this->openid_url_identity);
- $params['openid.trust_root'] = urlencode($this->URLs['trust_root']);
-
- if (isset($this->fields['required'])
- && (count($this->fields['required']) > 0)) {
- $params['openid.sreg.required'] = implode(',',$this->fields['required']);
- }
- if (isset($this->fields['optional'])
- && (count($this->fields['optional']) > 0)) {
- $params['openid.sreg.optional'] = implode(',',$this->fields['optional']);
- }
- return $this->URLs['openid_server'] . "?". $this->array2url($params);
- }
-
- function Redirect(){
- $redirect_to = $this->GetRedirectURL();
- if (headers_sent()){ // Use JavaScript to redirect if content has been previously sent (not recommended, but safe)
- echo '<script language="JavaScript" type="text/javascript">window.location=\'';
- echo $redirect_to;
- echo '\';</script>';
- }else{ // Default Header Redirect
- header('Location: ' . $redirect_to);
- }
- }
-
- function ValidateWithServer(){
- $params = array(
- 'openid.assoc_handle' => urlencode($_GET['openid_assoc_handle']),
- 'openid.signed' => urlencode($_GET['openid_signed']),
- 'openid.sig' => urlencode($_GET['openid_sig'])
- );
- // Send only required parameters to confirm validity
- $arr_signed = explode(",",str_replace('sreg.','sreg_',$_GET['openid_signed']));
- for ($i=0; $i<count($arr_signed); $i++){
- $s = str_replace('sreg_','sreg.', $arr_signed[$i]);
- $c = $_GET['openid_' . $arr_signed[$i]];
- // if ($c != ""){
- $params['openid.' . $s] = urlencode($c);
- // }
- }
- $params['openid.mode'] = "check_authentication";
-
- $openid_server = $this->GetOpenIDServer();
- if ($openid_server == false){
- return false;
- }
- $response = $this->CURL_Request($openid_server,'POST',$params);
- $data = $this->splitResponse($response);
-
- if ($data['is_valid'] == "true") {
- return true;
- }else{
- return false;
- }
- }
-}
diff --git a/apps/user_openid/phpmyid.php b/apps/user_openid/phpmyid.php
deleted file mode 100644
index 13fd31c47ca..00000000000
--- a/apps/user_openid/phpmyid.php
+++ /dev/null
@@ -1,1707 +0,0 @@
-<?php
-// PLEASE DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
-
-/**
- * phpMyID - A standalone, single user, OpenID Identity Provider
- *
- * @package phpMyID
- * @author CJ Niemira <siege (at) siege (dot) org>
- * @copyright 2006-2008
- * @license http://www.gnu.org/licenses/gpl.html GNU Public License
- * @url http://siege.org/projects/phpMyID
- * @version 0.9
- */
-
-/**
- * Set a constant to indicate that phpMyID is running
- */
-define('PHPMYID_STARTED', true);
-
-/**
- * List the known types and modes
- * @name $known
- * @global array $GLOBALS['known']
- */
-$GLOBALS['known'] = array(
- 'assoc_types' => array('HMAC-SHA1'),
-
- 'openid_modes' => array('accept',
- 'associate',
- 'authorize',
- 'cancel',
- 'checkid_immediate',
- 'checkid_setup',
- 'check_authentication',
- 'error',
- 'id_res',
- 'login',
- 'logout',
- 'test'),
-
- 'session_types' => array('',
- 'DH-SHA1'),
-
- 'bigmath_types' => array('DH-SHA1'),
-);
-
-/**
- * Defined by OpenID spec
- * @name $g
- * @global integer $GLOBALS['g']
- */
-$GLOBALS['g'] = 2;
-
-/**
- * Defined by OpenID spec
- * @name $p
- * @global integer $GLOBALS['p']
- */
-$GLOBALS['p'] = '155172898181473697471232257763715539915724801966915404479707' .
-'7953140576293785419175806512274236981889937278161526466314385615958256881888' .
-'8995127215884267541995034125870655654980358010487053768147672651325574704076' .
-'5857479291291572334510643245094715007229621094194349783925984760375594985848' .
-'253359305585439638443';
-
-
-// Runmode functions
-
-/**
- * Allow the user to accept trust on a URL
- * @global array $profile
- */
-function accept_mode () {
- global $profile;
-
- // this is a user session
- user_session();
-
- // the user needs refresh urls in their session to access this mode
- if (! isset($_SESSION['post_accept_url']) || ! isset($_SESSION['cancel_accept_url']) || ! isset($_SESSION['unaccepted_url']))
- error_500('You may not access this mode directly.');
-
- // has the user accepted the trust_root?
- $accepted = @strlen($_REQUEST['accepted'])
- ? $_REQUEST['accepted']
- : null;
-
- // if so, refresh back to post_accept_url
- if ($accepted === 'yes') {
- $_SESSION['accepted_url'] = $_SESSION['unaccepted_url'];
- wrap_redirect($_SESSION['post_accept_url']);
-
- // if they rejected it, return to the client
- } elseif ($accepted === 'no') {
- wrap_redirect($_SESSION['cancel_accept_url']);
- }
-
- // if neither, offer the trust request
- $q = strpos($profile['req_url'], '?') ? '&' : '?';
- $yes = $profile['req_url'] . $q . 'accepted=yes';
- $no = $profile['req_url'] . $q . 'accepted=no';
-
- wrap_html('The client site you are attempting to log into has requested that you trust the following URL:<br/><b>' . $_SESSION['unaccepted_url'] . '</b><br/><br/>Do you wish to continue?<br/><a href="' . $yes . '">Yes</a> | <a href="' . $no . '">No</a>');
-}
-
-/** * Perform an association with a consumer
- * @global array $known
- * @global array $profile
- * @global integer $g
- * @global integer $p
- */
-function associate_mode () {
- global $g, $known, $p, $profile;
-
- // Validate the request
- if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'associate')
- error_400();
-
- // Get the request options, using defaults as necessary
- $assoc_type = (@strlen($_REQUEST['openid_assoc_type'])
- && in_array($_REQUEST['openid_assoc_type'], $known['assoc_types']))
- ? $_REQUEST['openid_assoc_type']
- : 'HMAC-SHA1';
-
- $session_type = (@strlen($_REQUEST['openid_session_type'])
- && in_array($_REQUEST['openid_session_type'], $known['session_types']))
- ? $_REQUEST['openid_session_type']
- : '';
-
- $dh_modulus = (@strlen($_REQUEST['openid_dh_modulus']))
- ? long(base64_decode($_REQUEST['openid_dh_modulus']))
- : ($session_type == 'DH-SHA1'
- ? $p
- : null);
-
- $dh_gen = (@strlen($_REQUEST['openid_dh_gen']))
- ? long(base64_decode($_REQUEST['openid_dh_gen']))
- : ($session_type == 'DH-SHA1'
- ? $g
- : null);
-
- $dh_consumer_public = (@strlen($_REQUEST['openid_dh_consumer_public']))
- ? $_REQUEST['openid_dh_consumer_public']
- : ($session_type == 'DH-SHA1'
- ? error_post('dh_consumer_public was not specified')
- : null);
-
- $lifetime = time() + $profile['lifetime'];
-
- // Create standard keys
- $keys = array(
- 'assoc_type' => $assoc_type,
- 'expires_in' => $profile['lifetime']
- );
-
- // If I can't handle bigmath, default to plaintext sessions
- if (in_array($session_type, $known['bigmath_types']) && $profile['use_bigmath'] === false)
- $session_type = null;
-
- // Add response keys based on the session type
- switch ($session_type) {
- case 'DH-SHA1':
- // Create the associate id and shared secret now
- list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
-
- // Compute the Diffie-Hellman stuff
- $private_key = random($dh_modulus);
- $public_key = bmpowmod($dh_gen, $private_key, $dh_modulus);
- $remote_key = long(base64_decode($dh_consumer_public));
- $ss = bmpowmod($remote_key, $private_key, $dh_modulus);
-
- $keys['assoc_handle'] = $assoc_handle;
- $keys['session_type'] = $session_type;
- $keys['dh_server_public'] = base64_encode(bin($public_key));
- $keys['enc_mac_key'] = base64_encode(x_or(sha1_20(bin($ss)), $shared_secret));
-
- break;
-
- default:
- // Create the associate id and shared secret now
- list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
-
- $keys['assoc_handle'] = $assoc_handle;
- $keys['mac_key'] = base64_encode($shared_secret);
- }
-
- // Return the keys
- wrap_kv($keys);
-}
-
-
-/**
- * Perform a user authorization
- * @global array $profile
- */
-function authorize_mode () {
- global $profile;
- global $USERNAME;
- global $IDENTITY;
-
- // this is a user session
-
- // the user needs refresh urls in their session to access this mode
- if (! isset($_SESSION['post_auth_url']) || ! isset($_SESSION['cancel_auth_url']))
- error_500('You may not access this mode directly.');
-
- $profile['idp_url']=$IDENTITY;
- if (isset($_SERVER['PHP_AUTH_USER']) && $profile['authorized'] === false && $_SERVER['PHP_AUTH_USER']==$USERNAME) {
- if (OCP\User::checkPassword($USERNAME, $_SERVER['PHP_AUTH_PW'])) {// successful login!
- // return to the refresh url if they get in
- $_SESSION['openid_auth']=true;
- $_SESSION['openid_user']=$USERNAME;
- wrap_redirect($_SESSION['post_auth_url']);
-
- // failed login
- } else {
- $_SESSION['failures']++;
- debug('Login failed');
- debug('Fail count: ' . $_SESSION['failures']);
- }
-
- }
-
- // if we get this far the user is not authorized, so send the headers
- $uid = uniqid(mt_rand(1,9));
- $_SESSION['uniqid'] = $uid;
-
-// debug('Prompting user to log in. Stale? ' . $stale);
- header('HTTP/1.0 401 Unauthorized');
-// header(sprintf('WWW-Authenticate: Digest qop="auth-int, auth", realm="%s", domain="%s", nonce="%s", opaque="%s", stale="%s", algorithm="MD5"', $profile['auth_realm'], $profile['auth_domain'], $uid, md5($profile['auth_realm']), $stale ? 'true' : 'false'));
- header('WWW-Authenticate: Basic realm="ownCloud"');
- $q = strpos($_SESSION['cancel_auth_url'], '?') ? '&' : '?';
- wrap_refresh($_SESSION['cancel_auth_url'] . $q . 'openid.mode=cancel');
-// die('401 Unauthorized');
-}
-
-
-/**
- * Handle a consumer's request for cancellation.
- */
-function cancel_mode () {
- wrap_html('Request cancelled.');
-}
-
-
-/**
- * Handle a consumer's request to see if the user is authenticated
- */
-function check_authentication_mode () {
- // Validate the request
- if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'check_authentication')
- error_400();
-
- $assoc_handle = @strlen($_REQUEST['openid_assoc_handle'])
- ? $_REQUEST['openid_assoc_handle']
- : error_post('Missing assoc_handle');
-
- $sig = @strlen($_REQUEST['openid_sig'])
- ? $_REQUEST['openid_sig']
- : error_post('Missing sig');
-
- $signed = @strlen($_REQUEST['openid_signed'])
- ? $_REQUEST['openid_signed']
- : error_post('Missing signed');
-
- // Prepare the return keys
- $keys = array(
- 'openid.mode' => 'id_res'
- );
-
- // Invalidate the assoc handle if we need to
- if (@strlen($_REQUEST['openid_invalidate_handle'])) {
- destroy_assoc_handle($_REQUEST['openid_invalidate_handle']);
-
- $keys['invalidate_handle'] = $_REQUEST['openid_invalidate_handle'];
- }
-
- // Validate the sig by recreating the kv pair and signing
- $_REQUEST['openid_mode'] = 'id_res';
- $tokens = '';
- foreach (explode(',', $signed) as $param) {
- $post = preg_replace('/\./', '_', $param);
- $tokens .= sprintf("%s:%s\n", $param, $_REQUEST['openid_' . $post]);
- }
-
- // Add the sreg stuff, if we've got it
- if (isset($sreg_required)) {
- foreach (explode(',', $sreg_required) as $key) {
- if (! isset($sreg[$key]))
- continue;
- $skey = 'sreg.' . $key;
-
- $tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]);
- $keys[$skey] = $sreg[$key];
- $fields[] = $skey;
- }
- }
-
- // Look up the consumer's shared_secret and timeout
- list ($shared_secret, $expires) = secret($assoc_handle);
-
- // if I can't verify the assoc_handle, or if it's expired
- if ($shared_secret == false || (is_numeric($expires) && $expires < time())) {
- $keys['is_valid'] = 'false';
-
- } else {
- $ok = base64_encode(hmac($shared_secret, $tokens));
- $keys['is_valid'] = ($sig == $ok) ? 'true' : 'false';
- }
-
- // Return the keys
- wrap_kv($keys);
-}
-
-
-/**
- * Handle a consumer's request to see if the end user is logged in
- * @global array $known
- * @global array $profile
- * @global array $sreg
- */
-function checkid ( $wait ) {
- global $known, $profile, $sreg;
- global $USERNAME;
-
- // This is a user session
- user_session();
-
- // Get the options, use defaults as necessary
- $return_to = isset($_REQUEST['openid_return_to'])
- ? $_REQUEST['openid_return_to']
- : error_400('Missing return_to');
-
- $identity = isset($_REQUEST['openid_identity'])
- ? $_REQUEST['openid_identity']
- : error_get($return_to, 'Missing identity');
-
- $assoc_handle = isset($_REQUEST['openid_assoc_handle'])
- ? $_REQUEST['openid_assoc_handle']
- : null;
-
- $trust_root = isset($_REQUEST['openid_trust_root'])
- ? $_REQUEST['openid_trust_root']
- : $return_to;
-
- $sreg_required = isset($_REQUEST['openid_sreg_required'])
- ? $_REQUEST['openid_sreg.required']
- : '';
-
- $sreg_optional = isset($_REQUEST['openid_sreg_optional'])
- ? $_REQUEST['openid_sreg.optional']
- : '';
-
- // determine the cancel url
- $q = strpos($return_to, '?') ? '&' : '?';
- $cancel_url = $return_to . $q . 'openid.mode=cancel';
-
- // required and optional make no difference to us
- $sreg_required .= ',' . $sreg_optional;
- // do the trust_root analysis
- if ($trust_root != $return_to) {
- // the urls are not the same, be sure return decends from trust
- if (! url_descends($return_to, $trust_root))
- error_500('Invalid trust_root: "' . $trust_root . '"');
-
- }
-
- // transfer the user to the url accept mode if they're paranoid
- if ($wait == 1 && isset($profile['paranoid']) && $profile['paranoid'] === true && (! isset($_SESSION['accepted_url']) || $_SESSION['accepted_url'] != $trust_root)) {
- $_SESSION['cancel_accept_url'] = $cancel_url;
- $_SESSION['post_accept_url'] = $profile['req_url'];
- $_SESSION['unaccepted_url'] = $trust_root;
-
- debug('Transferring to acceptance mode.');
- debug('Cancel URL: ' . $_SESSION['cancel_accept_url']);
- debug('Post URL: ' . $_SESSION['post_accept_url']);
-
- $q = strpos($profile['idp_url'], '?') ? '&' : '?';
- wrap_redirect($profile['idp_url'] . $q . 'openid.mode=accept');
- }
-
- // make sure i am this identifier
-// if ($identity != $profile['idp_url']) {
-// debug("Invalid identity: $identity");
-// debug("IdP URL: " . $profile['idp_url']);
-// error_get($return_to, "Invalid identity: '$identity'");
-// }
-
- // begin setting up return keys
- $keys = array(
- 'mode' => 'id_res'
- );
-
- // if the user is not logged in, transfer to the authorization mode
- if ($USERNAME=='' || $_SESSION['openid_auth'] === false || $USERNAME != $_SESSION['openid_user']) {
- // users can only be logged in to one url at a time
- $_SESSION['openid_user'] = null;
- $_SESSION['auth_url'] = null;
-
- if ($wait) {
- unset($_SESSION['uniqid']);
-
- $_SESSION['cancel_auth_url'] = $cancel_url;
- $_SESSION['post_auth_url'] = $profile['req_url'];
-
- debug('Transferring to authorization mode.');
- debug('Cancel URL: ' . $_SESSION['cancel_auth_url']);
- debug('Post URL: ' . $_SESSION['post_auth_url']);
-
- $q = strpos($profile['idp_url'], '?') ? '&' : '?';
- wrap_redirect($profile['idp_url'] . $q . 'openid.mode=authorize');
- } else {
- $keys['user_setup_url'] = $profile['idp_url'];
- }
-
- // the user is logged in
- } else {
- // remove the refresh URLs if set
- unset($_SESSION['cancel_auth_url']);
- unset($_SESSION['post_auth_url']);
-
- // check the assoc handle
- list($shared_secret, $expires) = secret($assoc_handle);
-
- // if I can't verify the assoc_handle, or if it's expired
- if ($shared_secret == false || (is_numeric($expires) && $expires < time())) {
- debug("Session expired or missing key: $expires < " . time());
- if ($assoc_handle != null) {
- $keys['invalidate_handle'] = $assoc_handle;
- destroy_assoc_handle($assoc_handle);
- }
-
- $lifetime = time() + $profile['lifetime'];
- list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
- }
-
- $keys['identity'] = $profile['idp_url'];
- $keys['assoc_handle'] = $assoc_handle;
- $keys['return_to'] = $return_to;
-
- $fields = array_keys($keys);
- $tokens = '';
- foreach ($fields as $key)
- $tokens .= sprintf("%s:%s\n", $key, $keys[$key]);
-
- // add sreg keys
- foreach (explode(',', $sreg_required) as $key) {
- if (! isset($sreg[$key]))
- continue;
- $skey = 'sreg.' . $key;
-
- $tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]);
- $keys[$skey] = $sreg[$key];
- $fields[] = $skey;
- }
-
- $keys['signed'] = implode(',', $fields);
- $keys['sig'] = base64_encode(hmac($shared_secret, $tokens));
- }
-
- wrap_keyed_redirect($return_to, $keys);
-}
-
-
-/**
- * Handle a consumer's request to see if the user is already logged in
- */
-function checkid_immediate_mode () {
- if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_immediate')
- error_500();
-
- checkid(false);
-}
-
-
-/**
- * Handle a consumer's request to see if the user is logged in, but be willing
- * to wait for them to perform a login if they're not
- */
-function checkid_setup_mode () {
- if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_setup')
- error_500();
-
- checkid(true);
-}
-
-
-/**
- * Handle errors
- */
-function error_mode () {
- isset($_REQUEST['openid_error'])
- ? wrap_html($_REQUEST['openid_error'])
- : error_500();
-}
-
-
-/**
- * Show a user if they are logged in or not
- * @global array $profile
- */
-function id_res_mode () {
- global $profile;
-
- user_session();
-
- if ($profile['authorized'])
- wrap_html('You are logged in as ' . $_SESSION['auth_username']);
-
- wrap_html('You are not logged in');
-}
-
-
-/**
- * Allow a user to perform a static login
- * @global array $profile
- */
-function login_mode () {
- global $profile;
-
- user_session();
-
- if ($profile['authorized'])
- id_res_mode();
-
- $keys = array(
- 'mode' => 'checkid_setup',
- 'identity' => $profile['idp_url'],
- 'return_to' => $profile['idp_url']
- );
-
- wrap_keyed_redirect($profile['idp_url'], $keys);
-}
-
-
-/**
- * Allow a user to perform a static logout
- * @global array $profile
- */
-function logout_mode () {
- global $profile;
-
- user_session();
-
- if (! $profile['authorized'])
- wrap_html('You were not logged in');
-
- $_SESSION = array();
- session_destroy();
- debug('User session destroyed.');
-
- header('HTTP/1.0 401 Unauthorized');
- wrap_redirect($profile['idp_url']);
-}
-
-
-/**
- * The default information screen
- * @global array $profile
- */
-function no_mode () {
- global $USERNAME, $profile;
- $tmpl = new OCP\Template( 'user_openid', 'nomode', 'guest' );
- if(substr($profile['req_url'],-1,1)!=='/'){//the identity should always end with a /
- $profile['req_url'].='/';
- }
- $tmpl->addHeader('link',array('rel'=>'openid.server', 'href'=>$profile['req_url']));
- $tmpl->addHeader('link',array('rel'=>'openid.delegate', 'href'=>$profile['idp_url']));
- $tmpl->assign('user',$USERNAME);
- $tmpl->printPage();
-}
-
-
-/**
- * Testing for setup
- * @global array $profile
- */
-function test_mode () {
- global $profile, $p, $g;
-
- if ($profile['allow_test'] != true)
- error_403();
-
- @ini_set('max_execution_time', 180);
-
- $test_expire = time() + 120;
- $test_ss_enc = 'W7hvmld2yEYdDb0fHfSkKhQX+PM=';
- $test_ss = base64_decode($test_ss_enc);
- $test_token = "alpha:bravo\ncharlie:delta\necho:foxtrot";
- $test_server_private = '11263846781670293092494395517924811173145217135753406847875706165886322533899689335716152496005807017390233667003995430954419468996805220211293016296351031812246187748601293733816011832462964410766956326501185504714561648498549481477143603650090931135412673422192550825523386522507656442905243832471167330268';
- $test_client_public = base64_decode('AL63zqI5a5p8HdXZF5hFu8p+P9GOb816HcHuvNOhqrgkKdA3fO4XEzmldlb37nv3+xqMBgWj6gxT7vfuFerEZLBvuWyVvR7IOGZmx0BAByoq3fxYd3Fpe2Coxngs015vK37otmH8e83YyyGo5Qua/NAf13yz1PVuJ5Ctk7E+YdVc');
-
- $res = array();
-
- // bcmath
- $res['bcmath'] = extension_loaded('bcmath')
- ? 'pass' : 'warn - not loaded';
-
- // gmp
- if ($profile['allow_gmp']) {
- $res['gmp'] = extension_loaded('gmp')
- ? 'pass' : 'warn - not loaded';
- } else {
- $res['gmp'] = 'pass - n/a';
- }
-
- // get_temp_dir
- $res['logfile'] = is_writable($profile['logfile'])
- ? 'pass' : "warn - log is not writable";
-
- // session & new_assoc
- user_session();
- list($test_assoc, $test_new_ss) = new_assoc($test_expire);
- $res['session'] = ($test_assoc != session_id())
- ? 'pass' : 'fail';
-
- // secret
- @session_unregister('shared_secret');
- list($check, $check2) = secret($test_assoc);
- $res['secret'] = ($check == $test_new_ss)
- ? 'pass' : 'fail';
-
- // expire
- $res['expire'] = ($check2 <= $test_expire)
- ? 'pass' : 'fail';
-
- // base64
- $res['base64'] = (base64_encode($test_ss) == $test_ss_enc)
- ? 'pass' : 'fail';
-
- // hmac
- $test_sig = base64_decode('/VXgHvZAOdoz/OTa5+XJXzSGhjs=');
- $check = hmac($test_ss, $test_token);
- $res['hmac'] = ($check == $test_sig)
- ? 'pass' : sprintf("fail - '%s'", base64_encode($check));
-
- if ($profile['use_bigmath']) {
- // bigmath powmod
- $test_server_public = '102773334773637418574009974502372885384288396853657336911033649141556441102566075470916498748591002884433213640712303846640842555822818660704173387461364443541327856226098159843042567251113889701110175072389560896826887426539315893475252988846151505416694218615764823146765717947374855806613410142231092856731';
- $check = bmpowmod($g, $test_server_private, $p);
- $res['bmpowmod-1'] = ($check == $test_server_public)
- ? 'pass' : sprintf("fail - '%s'", $check);
-
- // long
- $test_client_long = '133926731803116519408547886573524294471756220428015419404483437186057383311250738749035616354107518232016420809434801736658109316293127101479053449990587221774635063166689561125137927607200322073086097478667514042144489248048756916881344442393090205172004842481037581607299263456852036730858519133859409417564';
- $res['long'] = (long($test_client_public) == $test_client_long)
- ? 'pass' : 'fail';
-
- // bigmath powmod 2
- $test_client_share = '19333275433742428703546496981182797556056709274486796259858099992516081822015362253491867310832140733686713353304595602619444380387600756677924791671971324290032515367930532292542300647858206600215875069588627551090223949962823532134061941805446571307168890255137575975911397744471376862555181588554632928402';
- $check = bmpowmod($test_client_long, $test_server_private, $p);
- $res['bmpowmod-2'] = ($check == $test_client_share)
- ? 'pass' : sprintf("fail - '%s'", $check);
-
- // bin
- $test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI=');
- $check = bin($test_client_share);
- $res['bin'] = ($check == $test_client_mac_s1)
- ? 'pass' : sprintf("fail - '%s'", base64_encode($check));
-
- } else {
- $res['bigmath'] = 'fail - big math functions are not available.';
- }
-
- // sha1_20
- $test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI=');
- $test_client_mac_s2 = base64_decode('0Mb2t9d/HvAZyuhbARJPYdx3+v4=');
- $check = sha1_20($test_client_mac_s1);
- $res['sha1_20'] = ($check == $test_client_mac_s2)
- ? 'pass' : sprintf("fail - '%s'", base64_encode($check));
-
- // x_or
- $test_client_mac_s3 = base64_decode('i36ZLYAJ1rYEx1VEHObrS8hgAg0=');
- $check = x_or($test_client_mac_s2, $test_ss);
- $res['x_or'] = ($check == $test_client_mac_s3)
- ? 'pass' : sprintf("fail - '%s'", base64_encode($check));
-
- $out = "<table border=1 cellpadding=4>\n";
- foreach ($res as $test => $stat) {
- $code = substr($stat, 0, 4);
- $color = ($code == 'pass') ? '#9f9'
- : (($code == 'warn') ? '#ff9' : '#f99');
- $out .= sprintf("<tr><th>%s</th><td style='background:%s'>%s</td></tr>\n", $test, $color, $stat);
- }
- $out .= "</table>";
-
- wrap_html( $out );
-}
-
-
-// Support functions
-
-/**
- * Prefix the keys of an array with 'openid.'
- * @param array $array
- * @return array
- */
-function append_openid ($array) {
- $keys = array_keys($array);
- $vals = array_values($array);
-
- $r = array();
- for ($i=0; $i<sizeof($keys); $i++)
- $r['openid.' . $keys[$i]] = $vals[$i];
- return $r;
-}
-
-/**
- * Create a big math addition function
- * @param string $l
- * @param string $r
- * @return string
- * @url http://www.icosaedro.it/bigint Inspired by
- */
-function bmadd($l, $r) {
- if (function_exists('bcadd'))
- return bcadd($l, $r);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_add($l, $r));
-
- $l = strval($l); $r = strval($r);
- $ll = strlen($l); $rl = strlen($r);
- if ($ll < $rl) {
- $l = str_repeat("0", $rl-$ll) . $l;
- $o = $rl;
-
- } elseif ( $ll > $rl ) {
- $r = str_repeat("0", $ll-$rl) . $r;
- $o = $ll;
-
- } else {
- $o = $ll;
- }
-
- $v = '';
- $carry = 0;
-
- for ($i = $o-1; $i >= 0; $i--) {
- $d = (int)$l[$i] + (int)$r[$i] + $carry;
- if ($d <= 9) {
- $carry = 0;
-
- } else {
- $carry = 1;
- $d -= 10;
- }
- $v = (string) $d . $v;
- }
-
- if ($carry > 0)
- $v = "1" . $v;
-
- return $v;
-}
-
-/**
- * Create a big math comparison function
- * @param string $l
- * @param string $r
- * @return string
- */
-function bmcomp($l, $r) {
- if (function_exists('bccomp'))
- return bccomp($l, $r);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_cmp($l, $r));
-
- $l = strval($l); $r = strval($r);
- $ll = strlen($l); $lr = strlen($r);
- if ($ll != $lr)
- return ($ll > $lr) ? 1 : -1;
-
- return strcmp($l, $r);
-}
-
-/**
- * Create a big math division function
- * @param string $l
- * @param string $r
- * @param int $z
- * @return string
- * @url http://www.icosaedro.it/bigint Inspired by
- */
-function bmdiv($l, $r, $z = 0) {
- if (function_exists('bcdiv'))
- return ($z == 0) ? bcdiv($l, $r) : bcmod($l, $r);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(($z == 0) ? gmp_div_q($l, $r) : gmp_mod($l, $r));
-
- $l = strval($l); $r = strval($r);
- $v = '0';
-
- while (true) {
- if( bmcomp($l, $r) < 0 )
- break;
-
- $delta = strlen($l) - strlen($r);
- if ($delta >= 1) {
- $zeroes = str_repeat("0", $delta);
- $r2 = $r . $zeroes;
-
- if (strcmp($l, $r2) >= 0) {
- $v = bmadd($v, "1" . $zeroes);
- $l = bmsub($l, $r2);
-
- } else {
- $zeroes = str_repeat("0", $delta - 1);
- $v = bmadd($v, "1" . $zeroes);
- $l = bmsub($l, $r . $zeroes);
- }
-
- } else {
- $l = bmsub($l, $r);
- $v = bmadd($v, "1");
- }
- }
-
- return ($z == 0) ? $v : $l;
-}
-
-/**
- * Create a big math multiplication function
- * @param string $l
- * @param string $r
- * @return string
- * @url http://www.icosaedro.it/bigint Inspired by
- */
-function bmmul($l, $r) {
- if (function_exists('bcmul'))
- return bcmul($l, $r);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_mul($l, $r));
-
- $l = strval($l); $r = strval($r);
-
- $v = '0';
- $z = '';
-
- for( $i = strlen($r)-1; $i >= 0; $i-- ){
- $bd = (int) $r[$i];
- $carry = 0;
- $p = "";
- for( $j = strlen($l)-1; $j >= 0; $j-- ){
- $ad = (int) $l[$j];
- $pd = $ad * $bd + $carry;
- if( $pd <= 9 ){
- $carry = 0;
- } else {
- $carry = (int) ($pd / 10);
- $pd = $pd % 10;
- }
- $p = (string) $pd . $p;
- }
- if( $carry > 0 )
- $p = (string) $carry . $p;
- $p = $p . $z;
- $z .= "0";
- $v = bmadd($v, $p);
- }
-
- return $v;
-}
-
-/**
- * Create a big math modulus function
- * @param string $value
- * @param string $mod
- * @return string
- */
-function bmmod( $value, $mod ) {
- if (function_exists('bcmod'))
- return bcmod($value, $mod);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_mod($value, $mod));
-
- $r = bmdiv($value, $mod, 1);
- return $r;
-}
-
-/**
- * Create a big math power function
- * @param string $value
- * @param string $exponent
- * @return string
- */
-function bmpow ($value, $exponent) {
- if (function_exists('bcpow'))
- return bcpow($value, $exponent);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_pow($value, $exponent));
-
- $r = '1';
- while ($exponent) {
- $r = bmmul($r, $value, 100);
- $exponent--;
- }
- return (string)rtrim($r, '0.');
-}
-
-/**
- * Create a big math 'powmod' function
- * @param string $value
- * @param string $exponent
- * @param string $mod
- * @return string
- * @url http://php.net/manual/en/function.bcpowmod.php#72704 Borrowed from
- */
-function bmpowmod ($value, $exponent, $mod) {
- if (function_exists('bcpowmod'))
- return bcpowmod($value, $exponent, $mod);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_powm($value, $exponent, $mod));
-
- $r = '';
- while ($exponent != '0') {
- $t = bmmod($exponent, '4096');
- $r = substr("000000000000" . decbin(intval($t)), -12) . $r;
- $exponent = bmdiv($exponent, '4096');
- }
-
- $r = preg_replace("!^0+!","",$r);
-
- if ($r == '')
- $r = '0';
- $value = bmmod($value, $mod);
- $erb = strrev($r);
- $q = '1';
- $a[0] = $value;
-
- for ($i = 1; $i < strlen($erb); $i++) {
- $a[$i] = bmmod( bmmul($a[$i-1], $a[$i-1]), $mod );
- }
-
- for ($i = 0; $i < strlen($erb); $i++) {
- if ($erb[$i] == "1") {
- $q = bmmod( bmmul($q, $a[$i]), $mod );
- }
- }
-
- return($q);
-}
-
-/**
- * Create a big math subtraction function
- * @param string $l
- * @param string $r
- * @return string
- * @url http://www.icosaedro.it/bigint Inspired by
- */
-function bmsub($l, $r) {
- if (function_exists('bcsub'))
- return bcsub($l, $r);
-
- global $profile;
- if ($profile['use_gmp'])
- return gmp_strval(gmp_sub($l, $r));
-
-
- $l = strval($l); $r = strval($r);
- $ll = strlen($l); $rl = strlen($r);
-
- if ($ll < $rl) {
- $l = str_repeat("0", $rl-$ll) . $l;
- $o = $rl;
- } elseif ( $ll > $rl ) {
- $r = str_repeat("0", $ll-$rl) . (string)$r;
- $o = $ll;
- } else {
- $o = $ll;
- }
-
- if (strcmp($l, $r) >= 0) {
- $sign = '';
- } else {
- $x = $l; $l = $r; $r = $x;
- $sign = '-';
- }
-
- $v = '';
- $carry = 0;
-
- for ($i = $o-1; $i >= 0; $i--) {
- $d = ($l[$i] - $r[$i]) - $carry;
- if ($d < 0) {
- $carry = 1;
- $d += 10;
- } else {
- $carry = 0;
- }
- $v = (string) $d . $v;
- }
-
- return $sign . ltrim($v, '0');
-}
-
-
-/**
- * Get a binary value
- * @param integer $n
- * @return string
- * @url http://openidenabled.com Borrowed from PHP-OpenID
- */
-function bin ($n) {
- $bytes = array();
- while (bmcomp($n, 0) > 0) {
- array_unshift($bytes, bmmod($n, 256));
- $n = bmdiv($n, bmpow(2,8));
- }
-
- if ($bytes && ($bytes[0] > 127))
- array_unshift($bytes, 0);
-
- $b = '';
- foreach ($bytes as $byte)
- $b .= pack('C', $byte);
-
- return $b;
-}
-
-
-/**
- * Debug logging
- * @param mixed $x
- * @param string $m
- */
-function debug ($x, $m = null) {
- global $profile;
-
- if (! isset($profile['debug']) || $profile['debug'] === false)
- return true;
-
- if (! is_writable(dirname($profile['logfile'])) &! is_writable($profile['logfile']))
- error_500('Cannot write to debug log: ' . $profile['logfile']);
-
- if (is_array($x)) {
- ob_start();
- print_r($x);
- $x = $m . ($m != null ? "\n" : '') . ob_get_clean();
-
- } else {
- $x .= "\n";
- }
-}
-
-
-/**
- * Destroy a consumer's assoc handle
- * @param string $id
- */
-function destroy_assoc_handle ( $id ) {
- debug("Destroying session: $id");
-
- $sid = session_id();
- session_write_close();
-
- session_id($id);
- if (OCP\Config::getSystemValue( "forcessl", false )) {
- ini_set("session.cookie_secure", "on");
- }
- session_start();
- session_destroy();
-
- session_id($sid);
- session_start();
-}
-
-
-/**
- * Return an error message to the user
- * @param string $message
- */
-function error_400 ( $message = 'Bad Request' ) {
- header("HTTP/1.1 400 Bad Request");
- wrap_html($message);
-}
-
-
-/**
- * Return an error message to the user
- * @param string $message
- */
-function error_403 ( $message = 'Forbidden' ) {
- header("HTTP/1.1 403 Forbidden");
- wrap_html($message);
-}
-
-
-/**
- * Return an error message to the user
- * @param string $message
- */
-function error_500 ( $message = 'Internal Server Error' ) {
- header("HTTP/1.1 500 Internal Server Error");
- wrap_html($message);
-}
-
-
-/**
- * Return an error message to the consumer
- * @param string $message
- */
-function error_get ( $url, $message = 'Bad Request') {
- wrap_keyed_redirect($url, array('mode' => 'error', 'error' => $message));
-}
-
-
-/**
- * Return an error message to the consumer
- * @param string $message
- */
-function error_post ( $message = 'Bad Request' ) {
- header("HTTP/1.1 400 Bad Request");
- echo ('error:' . $message);
- exit(0);
-}
-
-
-/**
- * Do an HMAC
- * @param string $key
- * @param string $data
- * @param string $hash
- * @return string
- * @url http://php.net/manual/en/function.sha1.php#39492 Borrowed from
- */
-function hmac($key, $data, $hash = 'sha1_20') {
- $blocksize=64;
-
- if (strlen($key) > $blocksize)
- $key = $hash($key);
-
- $key = str_pad($key, $blocksize,chr(0x00));
- $ipad = str_repeat(chr(0x36),$blocksize);
- $opad = str_repeat(chr(0x5c),$blocksize);
-
- $h1 = $hash(($key ^ $ipad) . $data);
- $hmac = $hash(($key ^ $opad) . $h1);
- return $hmac;
-}
-
-
-if (! function_exists('http_build_query')) {
-/**
- * Create function if missing
- * @param array $array
- * @return string
- */
-function http_build_query ($array) {
- $r = array();
- foreach ($array as $key => $val)
- $r[] = sprintf('%s=%s', urlencode($key), urlencode($val));
- return implode('&', $r);
-}}
-
-
-/**
- * Turn a binary back into a long
- * @param string $b
- * @return integer
- * @url http://openidenabled.com Borrowed from PHP-OpenID
- */
-function long($b) {
- $bytes = array_merge(unpack('C*', $b));
- $n = 0;
- foreach ($bytes as $byte) {
- $n = bmmul($n, bmpow(2,8));
- $n = bmadd($n, $byte);
- }
- return $n;
-}
-
-
-/**
- * Create a new consumer association
- * @param integer $expiration
- * @return array
- */
-function new_assoc ( $expiration ) {
- if (isset($_SESSION) && is_array($_SESSION)) {
- $sid = session_id();
- $dat = session_encode();
- session_write_close();
- }
-
- if (OCP\Config::getSystemValue( "forcessl", false )) {
- ini_set("session.cookie_secure", "on");
- }
- session_start();
- session_regenerate_id('false');
-
- $id = session_id();
- $shared_secret = new_secret();
- debug('Started new assoc session: ' . $id);
-
- $_SESSION = array();
- $_SESSION['expiration'] = $expiration;
- $_SESSION['shared_secret'] = base64_encode($shared_secret);
-
- session_write_close();
-
- if (isset($sid)) {
- session_id($sid);
- session_start();
- $_SESSION = array();
- session_decode($dat);
- }
-
- return array($id, $shared_secret);
-}
-
-
-/**
- * Create a new shared secret
- * @return string
- */
-function new_secret () {
- $r = '';
- for($i=0; $i<20; $i++)
- $r .= chr(mt_rand(0, 255));
-
- debug("Generated new key: hash = '" . md5($r) . "', length = '" . strlen($r) . "'");
- return $r;
-}
-
-
-/**
- * Random number generation
- * @param integer max
- * @return integer
- */
-function random ( $max ) {
- if (strlen($max) < 4)
- return mt_rand(1, $max - 1);
-
- $r = '';
- for($i=1; $i<strlen($max) - 1; $i++)
- $r .= mt_rand(0,9);
- $r .= mt_rand(1,9);
-
- return $r;
-}
-
-/**
- * Get the shared secret and expiration time for the specified assoc_handle
- * @param string $handle assoc_handle to look up
- * @return array (shared_secret, expiration_time)
- */
-function secret ( $handle ) {
- if (! preg_match('/^\w+$/', $handle))
- return array(false, 0);
-
- if (isset($_SESSION) && is_array($_SESSION)) {
- $sid = session_id();
- $dat = session_encode();
- session_write_close();
- }
-
- session_id($handle);
- if (OCP\Config::getSystemValue( "forcessl", false )) {
- ini_set("session.cookie_secure", "on");
- }
- session_start();
- debug('Started session to acquire key: ' . session_id());
-
- $secret = isset($_SESSION['shared_secret'])
- ? base64_decode($_SESSION['shared_secret'])
- : false;
-
- $expiration = isset($_SESSION['expiration'])
- ? $_SESSION['expiration']
- : null;
-
- session_write_close();
-
- if (isset($sid)) {
- session_id($sid);
- session_start();
- $_SESSION = array();
- session_decode($dat);
- }
-
- debug("Found key: hash = '" . md5($secret) . "', length = '" . strlen($secret) . "', expiration = '$expiration'");
- return array($secret, $expiration);
-}
-
-
-/**
- * Do an internal self check
- * @global array $profile
- * @global array $sreg
- */
-function self_check () {
- global $profile, $sreg;
-
-// if (! isset($profile) || ! is_array($profile))
-// error_500('No configuration found, you shouldn\'t access this file directly.');
-
- if (version_compare(phpversion(), '4.2.0', 'lt'))
- error_500('The required minimum version of PHP is 4.2.0, you are running ' . phpversion());
-
- $extension_r = array('session', 'pcre');
- foreach ($extension_r as $x) {
- if (! extension_loaded($x))
- @dl($x);
- if (! extension_loaded($x))
- error_500("Required extension '$x' is missing.");
- }
-
-// $extension_b = array('suhosin');
-// foreach ($extension_b as $x) {
-// if (extension_loaded($x) &! $profile["allow_$x"])
-// error_500("phpMyID is not compatible with '$x'");
-// }
-//
-// $keys = array('auth_username', 'auth_password');
-// foreach ($keys as $key) {
-// if (! array_key_exists($key, $profile))
-// error_500("'$key' is missing from your profile.");
-// }
-
- if (! isset($sreg) || ! is_array($sreg))
- $sreg = array();
-}
-
-
-/**
- * Do SHA1 20 byte encryption
- * @param string $v
- * @return string
- * @url http://openidenabled.com Borrowed from PHP-OpenID
- */
-function sha1_20 ($v) {
- if (version_compare(phpversion(), '5.0.0', 'ge'))
- return sha1($v, true);
-
- $hex = sha1($v);
- $r = '';
- for ($i = 0; $i < 40; $i += 2) {
- $hexcode = substr($hex, $i, 2);
- $charcode = base_convert($hexcode, 16, 10);
- $r .= chr($charcode);
- }
- return $r;
-}
-
-
-/**
- * Look for the point of differentiation in two strings
- * @param string $a
- * @param string $b
- * @return int
- */
-function str_diff_at ($a, $b) {
- if ($a == $b)
- return -1;
- $n = min(strlen($a), strlen($b));
- for ($i = 0; $i < $n; $i++)
- if ($a[$i] != $b[$i])
- return $i;
- return $n;
-}
-
-/**
- * Determine if a child URL actually decends from the parent, and that the
- * parent is a good URL.
- * THIS IS EXPERIMENTAL
- * @param string $parent
- * @param string $child
- * @return bool
- */
-function url_descends ( $child, $parent ) {
- if ($child == $parent)
- return true;
-
- $keys = array();
- $parts = array();
-
- $req = array('scheme', 'host');
- $bad = array('fragment', 'pass', 'user');
-
- foreach (array('parent', 'child') as $name) {
- $parts[$name] = @parse_url($$name);
- if ($parts[$name] === false)
- return false;
-
- $keys[$name] = array_keys($parts[$name]);
-
- if (array_intersect($keys[$name], $req) != $req)
- return false;
-
- if (array_intersect($keys[$name], $bad) != array())
- return false;
-
- if (! preg_match('/^https?$/i', strtolower($parts[$name]['scheme'])))
- return false;
-
- if (! array_key_exists('port', $parts[$name]))
- $parts[$name]['port'] = (strtolower($parts[$name]['scheme']) == 'https') ? 443 : 80;
-
- if (! array_key_exists('path', $parts[$name]))
- $parts[$name]['path'] = '/';
- }
-
- // port and scheme must match
- if ($parts['parent']['scheme'] != $parts['child']['scheme'] ||
- $parts['parent']['port'] != $parts['child']['port'])
- return false;
-
- // compare the hosts by reversing the strings
- $cr_host = strtolower(strrev($parts['child']['host']));
- $pr_host = strtolower(strrev($parts['parent']['host']));
-
- $break = str_diff_at($cr_host, $pr_host);
- if ($break >= 0 && ($pr_host[$break] != '*' || substr_count(substr($pr_host, 0, $break), '.') < 2))
- return false;
-
- // now compare the paths
- $break = str_diff_at($parts['child']['path'], $parts['parent']['path']);
- if ($break >= 0
- && ($break < strlen($parts['parent']['path']) && $parts['parent']['path'][$break] != '*')
- || ($break > strlen($parts['child']['path'])))
- return false;
-
- return true;
-}
-
-
-/**
- * Create a user session
- * @global array $profile
- * @global array $proto
- */
-function user_session () {
- global $proto, $profile;
-
- session_name('phpMyID_Server');
- if (OCP\Config::getSystemValue( "forcessl", false )) {
- ini_set("session.cookie_secure", "on");
- }
- @session_start();
-
- $profile['authorized'] = (isset($_SESSION['auth_username'])
- && $_SESSION['auth_username'] == $profile['auth_username'])
- ? true
- : false;
-
- debug('Started user session: ' . session_id() . ' Auth? ' . $profile['authorized']);
-}
-
-
-/**
- * Return HTML
- * @global string $charset
- * @param string $message
- */
-function wrap_html ( $message ) {
- global $charset, $profile;
- header('Content-Type: text/html; charset=' . $charset);
- $html= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<title>phpMyID</title>
-<link rel="openid.server" href="' . $profile['req_url'] . '" />
-<link rel="openid.delegate" href="' . $profile['idp_url'] . '" />
-' . implode("\n", $profile['opt_headers']) . '
-<meta name="charset" content="' . $charset . '" />
-<meta name="robots" content="noindex,nofollow" />
-</head>
-<body>
-<p>' . $message . '</p>
-</body>
-</html>
-';
- echo $html;
- exit(0);
-}
-
-
-/**
- * Return a key-value pair in plain text
- * @global string $charset
- * @param array $keys
- */
-function wrap_kv ( $keys ) {
- global $charset;
-
- debug($keys, 'Wrapped key/vals');
- header('Content-Type: text/plain; charset=' . $charset);
- foreach ($keys as $key => $value)
- printf("%s:%s\n", $key, $value);
-
- exit(0);
-}
-
-
-/**
- * Redirect, with OpenID keys
- * @param string $url
- * @param array @keys
- */
-function wrap_keyed_redirect ($url, $keys) {
- $keys = append_openid($keys);
- debug($keys, 'Location keys');
-
- $q = strpos($url, '?') ? '&' : '?';
- wrap_redirect($url . $q . http_build_query($keys));
-}
-
-
-/**
- * Redirect the browser
- * @global string $charset
- * @param string $url
- */
-function wrap_redirect ($url) {
- header('HTTP/1.1 302 Found');
- header('Location: ' . $url);
- debug('Location: ' . $url);
- exit(0);
-}
-
-/**
- * Return an HTML refresh
- * @global string $charset
- * @param string $url
- */
-function wrap_refresh ($url) {
- global $charset;
-
- header('Content-Type: text/html; charset=' . $charset);
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<title>phpMyID</title>
-<meta http-equiv="refresh" content="0;url=' . $url . '">
-</head>
-<body>
-<p>Redirecting to <a href="' . $url . '">' . $url . '</a></p>
-</body>
-</html>
-';
-
- debug('Refresh: ' . $url);
- exit(0);
-}
-
-
-/**
- * Implement binary x_or
- * @param string $a
- * @param string $b
- * @return string
- */
-function x_or ($a, $b) {
- $r = "";
-
- for ($i = 0; $i < strlen($b); $i++)
- $r .= $a[$i] ^ $b[$i];
- debug("Xor size: " . strlen($r));
- return $r;
-}
-
-
-
-/*
- * App Initialization
- */
-// Determine the charset to use
-$GLOBALS['charset'] = 'iso-8859-1';
-
-// Set the internal encoding
-if (function_exists('mb_internal_encoding'))
- mb_internal_encoding($charset);
-
-// Avoid problems with non-default arg_separator.output settings
-// Credit for this goes to user 'prelog' on the forums
-ini_set('arg_separator.output', '&');
-
-// Do a check to be sure everything is set up correctly
-self_check();
-
-
-/**
- * Determine the HTTP request port
- * @name $port
- * @global integer $GLOBALS['port']
- */
-$GLOBALS['port'] = ((isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' && $_SERVER['SERVER_PORT'] == 443)
- || $_SERVER['SERVER_PORT'] == 80)
- ? ''
- : ':' . $_SERVER['SERVER_PORT'];
-
-
-/**
- * Determine the HTTP request protocol
- * @name $proto
- * @global string $GLOBALS['proto']
- */
-$GLOBALS['proto'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
-
-// Set the authorization state - DO NOT OVERRIDE
-$profile['authorized'] = false;
-
-global $IDENTITY;
-global $USERNAME;
-
-// Set a default IDP URL
-if (! array_key_exists('idp_url', $profile))
- $profile['idp_url'] = $IDENTITY;
-
-//Determine the requested URL - DO NOT OVERRIDE
-$profile['req_url'] = sprintf("%s://%s%s",
- $proto,
- OCP\Util::getServerHost(),
-// $port,//host already includes the path
- $_SERVER["REQUEST_URI"]);
-
-
-// Set the default allowance for testing
-if (! array_key_exists('allow_test', $profile))
- $profile['allow_test'] = false;
-
-// Set the default allowance for gmp
-if (! array_key_exists('allow_gmp', $profile))
- $profile['allow_gmp'] = false;
-
-// Set the default force bigmath - BAD IDEA to override this
-if (! array_key_exists('force_bigmath', $profile))
- $profile['force_bigmath'] = false;
-
-// Determine if GMP is usable
-$profile['use_gmp'] = (extension_loaded('gmp') && $profile['allow_gmp']) ? true : false;
-
-// Determine if I can perform big math functions
-$profile['use_bigmath'] = (extension_loaded('bcmath') || $profile['use_gmp'] || $profile['force_bigmath']) ? true : false;
-
-// Set a default authentication domain
-if (! array_key_exists('auth_domain', $profile))
- $profile['auth_domain'] = $profile['req_url'] . ' ' . $profile['idp_url'];
-
-// Set a default authentication realm
-if (! array_key_exists('auth_realm', $profile))
- $profile['auth_realm'] = 'ownCloud';
-
-// Determine the realm for digest authentication - DO NOT OVERRIDE
-$profile['php_realm'] = $profile['auth_realm'] . (ini_get('safe_mode') ? '-' . getmyuid() : '');
-
-// Set a default lifetime - the lesser of GC and cache time
-if (! array_key_exists('lifetime', $profile)) {
- $sce = session_cache_expire() * 60;
- $gcm = ini_get('session.gc_maxlifetime');
- $profile['lifetime'] = $sce < $gcm ? $sce : $gcm;
-}
-
-// Set a default log file
-if (! array_key_exists('logfile', $profile))
- $profile['logfile'] = get_temp_dir() . DIRECTORY_SEPARATOR . $profile['auth_realm'] . '.debug.log';
-
-
-/*
- * Optional Initialization
- */
-// Setup optional headers
-$profile['opt_headers'] = array();
-
-// Determine if I should add microid stuff
-if (array_key_exists('microid', $profile)) {
- $hash = sha1($profile['idp_url']);
- $values = is_array($profile['microid']) ? $profile['microid'] : array($profile['microid']);
-
- foreach ($values as $microid) {
- preg_match('/^([a-z]+)/i', $microid, $mtx);
- $profile['opt_headers'][] = sprintf('<meta name="microid" content="%s+%s:sha1:%s" />', $mtx[1], $proto, sha1(sha1($microid) . $hash));
- }
-}
-
-// Determine if I should add pavatar stuff
-if (array_key_exists('pavatar', $profile))
- $profile['opt_headers'][] = sprintf('<link rel="pavatar" href="%s" />', $profile['pavatar']);
-
-
-/*
- * Do it
- */
-// Decide which runmode, based on user request or default
-$run_mode = (isset($_REQUEST['openid_mode'])
- && in_array($_REQUEST['openid_mode'], $known['openid_modes']))
- ? $_REQUEST['openid_mode']
- : 'no';
-
-// Run in the determined runmode
-debug("Run mode: $run_mode at: " . time());
-debug($_REQUEST, 'Request params');
-call_user_func($run_mode . '_mode');
diff --git a/apps/user_openid/user.php b/apps/user_openid/user.php
index d25b95259e0..88571ba618e 100644
--- a/apps/user_openid/user.php
+++ b/apps/user_openid/user.php
@@ -44,4 +44,4 @@ if(!OCP\User::userExists($USERNAME)){
}
$IDENTITY=OCP\Util::linkToAbsolute( "user_openid", "user.php" ).'/'.$USERNAME;
-require_once 'phpmyid.php';
+require_once 'openid/phpmyid.php';
diff --git a/apps/user_openid/user_openid.php b/apps/user_openid/user_openid.php
index 70b193a30b1..19f2f719b06 100644
--- a/apps/user_openid/user_openid.php
+++ b/apps/user_openid/user_openid.php
@@ -21,7 +21,7 @@
*
*/
-require_once('class.openid.v3.php');
+require_once('openid/class.openid.v3.php');
/**
* Class for user OpenId backend