aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart Visscher <bartv@thisnet.nl>2012-07-24 18:35:09 +0200
committerBart Visscher <bartv@thisnet.nl>2012-07-24 18:35:09 +0200
commit0040b7109f1201805d9e4ac7e586b44261c335a4 (patch)
tree852fdb4394e8ab3bfb2bdb4300e542e8abbb7d80
parent768b44b9b685a07af6030e484ab6322ba44b5b7e (diff)
parent856d9c0b54cc971940df4ed64429d994faf770f9 (diff)
downloadnextcloud-server-0040b7109f1201805d9e4ac7e586b44261c335a4.tar.gz
nextcloud-server-0040b7109f1201805d9e4ac7e586b44261c335a4.zip
Merge branch 'master' into routing
Conflicts: lib/ocs.php
-rw-r--r--3rdparty/miniColors/GPL-LICENSE.txt278
-rw-r--r--3rdparty/miniColors/MIT-LICENSE.txt20
-rwxr-xr-x3rdparty/miniColors/css/images/colors.pngbin0 -> 12485 bytes
-rwxr-xr-x3rdparty/miniColors/css/images/trigger.pngbin0 -> 1406 bytes
-rwxr-xr-x3rdparty/miniColors/css/jquery.miniColors.css81
-rwxr-xr-x3rdparty/miniColors/js/jquery.miniColors.js580
-rwxr-xr-x3rdparty/miniColors/js/jquery.miniColors.min.js9
-rw-r--r--3rdparty/openid/class.openid.v3.php (renamed from apps/user_openid/class.openid.v3.php)0
-rw-r--r--3rdparty/openid/phpmyid.php (renamed from apps/user_openid/phpmyid.php)0
-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/lib/calendar.php36
-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.js600
-rw-r--r--apps/contacts/js/loader.js4
-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/user_migrate/templates/settings.php2
-rw-r--r--apps/user_openid/appinfo/app.php2
-rw-r--r--apps/user_openid/user.php2
-rw-r--r--apps/user_openid/user_openid.php2
-rw-r--r--core/css/styles.css2
-rw-r--r--core/js/eventsource.js1
-rw-r--r--core/templates/exception.php30
-rw-r--r--core/templates/layout.user.php1
-rwxr-xr-xlib/app.php6
-rw-r--r--lib/cache.php108
-rw-r--r--lib/cache/apc.php5
-rw-r--r--lib/cache/broker.php6
-rw-r--r--lib/cache/file.php5
-rw-r--r--lib/cache/xcache.php5
-rw-r--r--lib/connector/sabre/node.php1
-rw-r--r--lib/db.php6
-rw-r--r--lib/eventsource.php3
-rw-r--r--lib/exception.php93
-rw-r--r--lib/filecache.php32
-rw-r--r--lib/filesystem.php186
-rw-r--r--lib/filesystemview.php436
-rw-r--r--lib/helper.php31
-rw-r--r--lib/image.php13
-rw-r--r--lib/installer.php30
-rw-r--r--lib/json.php14
-rw-r--r--lib/mimetypes.fixlist.php22
-rw-r--r--lib/mimetypes.list.php13
-rw-r--r--lib/minimizer.php10
-rw-r--r--lib/ocs.php964
-rw-r--r--lib/user.php8
-rwxr-xr-xlib/util.php59
-rw-r--r--ocs/providers.php4
-rw-r--r--tests/lib/cache.php21
-rw-r--r--tests/lib/cache/file.php19
65 files changed, 3455 insertions, 1341 deletions
diff --git a/3rdparty/miniColors/GPL-LICENSE.txt b/3rdparty/miniColors/GPL-LICENSE.txt
new file mode 100644
index 00000000000..11dddd00ef0
--- /dev/null
+++ b/3rdparty/miniColors/GPL-LICENSE.txt
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/3rdparty/miniColors/MIT-LICENSE.txt b/3rdparty/miniColors/MIT-LICENSE.txt
new file mode 100644
index 00000000000..ec6f7581576
--- /dev/null
+++ b/3rdparty/miniColors/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) Cory LaViska
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/3rdparty/miniColors/css/images/colors.png b/3rdparty/miniColors/css/images/colors.png
new file mode 100755
index 00000000000..1b4f819d8d9
--- /dev/null
+++ b/3rdparty/miniColors/css/images/colors.png
Binary files differ
diff --git a/3rdparty/miniColors/css/images/trigger.png b/3rdparty/miniColors/css/images/trigger.png
new file mode 100755
index 00000000000..8c169fd6053
--- /dev/null
+++ b/3rdparty/miniColors/css/images/trigger.png
Binary files differ
diff --git a/3rdparty/miniColors/css/jquery.miniColors.css b/3rdparty/miniColors/css/jquery.miniColors.css
new file mode 100755
index 00000000000..381bc1dc065
--- /dev/null
+++ b/3rdparty/miniColors/css/jquery.miniColors.css
@@ -0,0 +1,81 @@
+.miniColors-trigger {
+ height: 22px;
+ width: 22px;
+ background: url(images/trigger.png) center no-repeat;
+ vertical-align: middle;
+ margin: 0 .25em;
+ display: inline-block;
+ outline: none;
+}
+
+.miniColors-selector {
+ position: absolute;
+ width: 175px;
+ height: 150px;
+ background: #FFF;
+ border: solid 1px #BBB;
+ -moz-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
+ -webkit-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
+ box-shadow: 0 0 6px rgba(0, 0, 0, .25);
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ padding: 5px;
+ z-index: 999999;
+}
+
+.miniColors-selector.black {
+ background: #000;
+ border-color: #000;
+}
+
+.miniColors-colors {
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ width: 150px;
+ height: 150px;
+ background: url(images/colors.png) right no-repeat;
+ cursor: crosshair;
+}
+
+.miniColors-hues {
+ position: absolute;
+ top: 5px;
+ left: 160px;
+ width: 20px;
+ height: 150px;
+ background: url(images/colors.png) left no-repeat;
+ cursor: crosshair;
+}
+
+.miniColors-colorPicker {
+ position: absolute;
+ width: 9px;
+ height: 9px;
+ border: 1px solid #fff;
+ -moz-border-radius: 11px;
+ -webkit-border-radius: 11px;
+ border-radius: 11px;
+}
+.miniColors-colorPicker-inner {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 7px;
+ height: 7px;
+ border: 1px solid #000;
+ -moz-border-radius: 9px;
+ -webkit-border-radius: 9px;
+ border-radius: 9px;
+}
+
+.miniColors-huePicker {
+ position: absolute;
+ left: -3px;
+ width: 24px;
+ height: 1px;
+ border: 1px solid #fff;
+ border-radius: 2px;
+ background: #000;
+} \ No newline at end of file
diff --git a/3rdparty/miniColors/js/jquery.miniColors.js b/3rdparty/miniColors/js/jquery.miniColors.js
new file mode 100755
index 00000000000..187db3fa84e
--- /dev/null
+++ b/3rdparty/miniColors/js/jquery.miniColors.js
@@ -0,0 +1,580 @@
+/*
+ * jQuery miniColors: A small color selector
+ *
+ * Copyright 2011 Cory LaViska for A Beautiful Site, LLC. (http://abeautifulsite.net/)
+ *
+ * Dual licensed under the MIT or GPL Version 2 licenses
+ *
+*/
+if(jQuery) (function($) {
+
+ $.extend($.fn, {
+
+ miniColors: function(o, data) {
+
+ var create = function(input, o, data) {
+ //
+ // Creates a new instance of the miniColors selector
+ //
+
+ // Determine initial color (defaults to white)
+ var color = expandHex(input.val());
+ if( !color ) color = 'ffffff';
+ var hsb = hex2hsb(color);
+
+ // Create trigger
+ var trigger = $('<a class="miniColors-trigger" style="background-color: #' + color + '" href="#"></a>');
+ trigger.insertAfter(input);
+
+ // Set input data and update attributes
+ input
+ .addClass('miniColors')
+ .data('original-maxlength', input.attr('maxlength') || null)
+ .data('original-autocomplete', input.attr('autocomplete') || null)
+ .data('letterCase', 'uppercase')
+ .data('trigger', trigger)
+ .data('hsb', hsb)
+ .data('change', o.change ? o.change : null)
+ .data('close', o.close ? o.close : null)
+ .data('open', o.open ? o.open : null)
+ .attr('maxlength', 7)
+ .attr('autocomplete', 'off')
+ .val('#' + convertCase(color, o.letterCase));
+
+ // Handle options
+ if( o.readonly ) input.prop('readonly', true);
+ if( o.disabled ) disable(input);
+
+ // Show selector when trigger is clicked
+ trigger.bind('click.miniColors', function(event) {
+ event.preventDefault();
+ if( input.val() === '' ) input.val('#');
+ show(input);
+
+ });
+
+ // Show selector when input receives focus
+ input.bind('focus.miniColors', function(event) {
+ if( input.val() === '' ) input.val('#');
+ show(input);
+ });
+
+ // Hide on blur
+ input.bind('blur.miniColors', function(event) {
+ var hex = expandHex( hsb2hex(input.data('hsb')) );
+ input.val( hex ? '#' + convertCase(hex, input.data('letterCase')) : '' );
+ });
+
+ // Hide when tabbing out of the input
+ input.bind('keydown.miniColors', function(event) {
+ if( event.keyCode === 9 ) hide(input);
+ });
+
+ // Update when color is typed in
+ input.bind('keyup.miniColors', function(event) {
+ setColorFromInput(input);
+ });
+
+ // Handle pasting
+ input.bind('paste.miniColors', function(event) {
+ // Short pause to wait for paste to complete
+ setTimeout( function() {
+ setColorFromInput(input);
+ }, 5);
+ });
+
+ };
+
+ var destroy = function(input) {
+ //
+ // Destroys an active instance of the miniColors selector
+ //
+
+ hide();
+ input = $(input);
+
+ // Restore to original state
+ input.data('trigger').remove();
+ input
+ .attr('autocomplete', input.data('original-autocomplete'))
+ .attr('maxlength', input.data('original-maxlength'))
+ .removeData()
+ .removeClass('miniColors')
+ .unbind('.miniColors');
+ $(document).unbind('.miniColors');
+ };
+
+ var enable = function(input) {
+ //
+ // Enables the input control and the selector
+ //
+ input
+ .prop('disabled', false)
+ .data('trigger')
+ .css('opacity', 1);
+ };
+
+ var disable = function(input) {
+ //
+ // Disables the input control and the selector
+ //
+ hide(input);
+ input
+ .prop('disabled', true)
+ .data('trigger')
+ .css('opacity', 0.5);
+ };
+
+ var show = function(input) {
+ //
+ // Shows the miniColors selector
+ //
+ if( input.prop('disabled') ) return false;
+
+ // Hide all other instances
+ hide();
+
+ // Generate the selector
+ var selector = $('<div class="miniColors-selector"></div>');
+ selector
+ .append('<div class="miniColors-colors" style="background-color: #FFF;"><div class="miniColors-colorPicker"><div class="miniColors-colorPicker-inner"></div></div>')
+ .append('<div class="miniColors-hues"><div class="miniColors-huePicker"></div></div>')
+ .css({
+ top: input.is(':visible') ? input.offset().top + input.outerHeight() : input.data('trigger').offset().top + input.data('trigger').outerHeight(),
+ left: input.is(':visible') ? input.offset().left : input.data('trigger').offset().left,
+ display: 'none'
+ })
+ .addClass( input.attr('class') );
+
+ // Set background for colors
+ var hsb = input.data('hsb');
+ selector
+ .find('.miniColors-colors')
+ .css('backgroundColor', '#' + hsb2hex({ h: hsb.h, s: 100, b: 100 }));
+
+ // Set colorPicker position
+ var colorPosition = input.data('colorPosition');
+ if( !colorPosition ) colorPosition = getColorPositionFromHSB(hsb);
+ selector.find('.miniColors-colorPicker')
+ .css('top', colorPosition.y + 'px')
+ .css('left', colorPosition.x + 'px');
+
+ // Set huePicker position
+ var huePosition = input.data('huePosition');
+ if( !huePosition ) huePosition = getHuePositionFromHSB(hsb);
+ selector.find('.miniColors-huePicker').css('top', huePosition.y + 'px');
+
+ // Set input data
+ input
+ .data('selector', selector)
+ .data('huePicker', selector.find('.miniColors-huePicker'))
+ .data('colorPicker', selector.find('.miniColors-colorPicker'))
+ .data('mousebutton', 0);
+
+ $('BODY').append(selector);
+ selector.fadeIn(100);
+
+ // Prevent text selection in IE
+ selector.bind('selectstart', function() { return false; });
+
+ $(document).bind('mousedown.miniColors touchstart.miniColors', function(event) {
+
+ input.data('mousebutton', 1);
+ var testSubject = $(event.target).parents().andSelf();
+
+ if( testSubject.hasClass('miniColors-colors') ) {
+ event.preventDefault();
+ input.data('moving', 'colors');
+ moveColor(input, event);
+ }
+
+ if( testSubject.hasClass('miniColors-hues') ) {
+ event.preventDefault();
+ input.data('moving', 'hues');
+ moveHue(input, event);
+ }
+
+ if( testSubject.hasClass('miniColors-selector') ) {
+ event.preventDefault();
+ return;
+ }
+
+ if( testSubject.hasClass('miniColors') ) return;
+
+ hide(input);
+ });
+
+ $(document)
+ .bind('mouseup.miniColors touchend.miniColors', function(event) {
+ event.preventDefault();
+ input.data('mousebutton', 0).removeData('moving');
+ })
+ .bind('mousemove.miniColors touchmove.miniColors', function(event) {
+ event.preventDefault();
+ if( input.data('mousebutton') === 1 ) {
+ if( input.data('moving') === 'colors' ) moveColor(input, event);
+ if( input.data('moving') === 'hues' ) moveHue(input, event);
+ }
+ });
+
+ // Fire open callback
+ if( input.data('open') ) {
+ input.data('open').call(input.get(0), '#' + hsb2hex(hsb), hsb2rgb(hsb));
+ }
+
+ };
+
+ var hide = function(input) {
+
+ //
+ // Hides one or more miniColors selectors
+ //
+
+ // Hide all other instances if input isn't specified
+ if( !input ) input = '.miniColors';
+
+ $(input).each( function() {
+ var selector = $(this).data('selector');
+ $(this).removeData('selector');
+ $(selector).fadeOut(100, function() {
+ // Fire close callback
+ if( input.data('close') ) {
+ var hsb = input.data('hsb'), hex = hsb2hex(hsb);
+ input.data('close').call(input.get(0), '#' + hex, hsb2rgb(hsb));
+ }
+ $(this).remove();
+ });
+ });
+
+ $(document).unbind('.miniColors');
+
+ };
+
+ var moveColor = function(input, event) {
+
+ var colorPicker = input.data('colorPicker');
+
+ colorPicker.hide();
+
+ var position = {
+ x: event.pageX,
+ y: event.pageY
+ };
+
+ // Touch support
+ if( event.originalEvent.changedTouches ) {
+ position.x = event.originalEvent.changedTouches[0].pageX;
+ position.y = event.originalEvent.changedTouches[0].pageY;
+ }
+ position.x = position.x - input.data('selector').find('.miniColors-colors').offset().left - 5;
+ position.y = position.y - input.data('selector').find('.miniColors-colors').offset().top - 5;
+ if( position.x <= -5 ) position.x = -5;
+ if( position.x >= 144 ) position.x = 144;
+ if( position.y <= -5 ) position.y = -5;
+ if( position.y >= 144 ) position.y = 144;
+
+ input.data('colorPosition', position);
+ colorPicker.css('left', position.x).css('top', position.y).show();
+
+ // Calculate saturation
+ var s = Math.round((position.x + 5) * 0.67);
+ if( s < 0 ) s = 0;
+ if( s > 100 ) s = 100;
+
+ // Calculate brightness
+ var b = 100 - Math.round((position.y + 5) * 0.67);
+ if( b < 0 ) b = 0;
+ if( b > 100 ) b = 100;
+
+ // Update HSB values
+ var hsb = input.data('hsb');
+ hsb.s = s;
+ hsb.b = b;
+
+ // Set color
+ setColor(input, hsb, true);
+ };
+
+ var moveHue = function(input, event) {
+
+ var huePicker = input.data('huePicker');
+
+ huePicker.hide();
+
+ var position = {
+ y: event.pageY
+ };
+
+ // Touch support
+ if( event.originalEvent.changedTouches ) {
+ position.y = event.originalEvent.changedTouches[0].pageY;
+ }
+
+ position.y = position.y - input.data('selector').find('.miniColors-colors').offset().top - 1;
+ if( position.y <= -1 ) position.y = -1;
+ if( position.y >= 149 ) position.y = 149;
+ input.data('huePosition', position);
+ huePicker.css('top', position.y).show();
+
+ // Calculate hue
+ var h = Math.round((150 - position.y - 1) * 2.4);
+ if( h < 0 ) h = 0;
+ if( h > 360 ) h = 360;
+
+ // Update HSB values
+ var hsb = input.data('hsb');
+ hsb.h = h;
+
+ // Set color
+ setColor(input, hsb, true);
+
+ };
+
+ var setColor = function(input, hsb, updateInput) {
+ input.data('hsb', hsb);
+ var hex = hsb2hex(hsb);
+ if( updateInput ) input.val( '#' + convertCase(hex, input.data('letterCase')) );
+ input.data('trigger').css('backgroundColor', '#' + hex);
+ if( input.data('selector') ) input.data('selector').find('.miniColors-colors').css('backgroundColor', '#' + hsb2hex({ h: hsb.h, s: 100, b: 100 }));
+
+ // Fire change callback
+ if( input.data('change') ) {
+ if( hex === input.data('lastChange') ) return;
+ input.data('change').call(input.get(0), '#' + hex, hsb2rgb(hsb));
+ input.data('lastChange', hex);
+ }
+
+ };
+
+ var setColorFromInput = function(input) {
+
+ input.val('#' + cleanHex(input.val()));
+ var hex = expandHex(input.val());
+ if( !hex ) return false;
+
+ // Get HSB equivalent
+ var hsb = hex2hsb(hex);
+
+ // If color is the same, no change required
+ var currentHSB = input.data('hsb');
+ if( hsb.h === currentHSB.h && hsb.s === currentHSB.s && hsb.b === currentHSB.b ) return true;
+
+ // Set colorPicker position
+ var colorPosition = getColorPositionFromHSB(hsb);
+ var colorPicker = $(input.data('colorPicker'));
+ colorPicker.css('top', colorPosition.y + 'px').css('left', colorPosition.x + 'px');
+ input.data('colorPosition', colorPosition);
+
+ // Set huePosition position
+ var huePosition = getHuePositionFromHSB(hsb);
+ var huePicker = $(input.data('huePicker'));
+ huePicker.css('top', huePosition.y + 'px');
+ input.data('huePosition', huePosition);
+
+ setColor(input, hsb);
+
+ return true;
+
+ };
+
+ var convertCase = function(string, letterCase) {
+ if( letterCase === 'lowercase' ) return string.toLowerCase();
+ if( letterCase === 'uppercase' ) return string.toUpperCase();
+ return string;
+ };
+
+ var getColorPositionFromHSB = function(hsb) {
+ var x = Math.ceil(hsb.s / 0.67);
+ if( x < 0 ) x = 0;
+ if( x > 150 ) x = 150;
+ var y = 150 - Math.ceil(hsb.b / 0.67);
+ if( y < 0 ) y = 0;
+ if( y > 150 ) y = 150;
+ return { x: x - 5, y: y - 5 };
+ };
+
+ var getHuePositionFromHSB = function(hsb) {
+ var y = 150 - (hsb.h / 2.4);
+ if( y < 0 ) h = 0;
+ if( y > 150 ) h = 150;
+ return { y: y - 1 };
+ };
+
+ var cleanHex = function(hex) {
+ return hex.replace(/[^A-F0-9]/ig, '');
+ };
+
+ var expandHex = function(hex) {
+ hex = cleanHex(hex);
+ if( !hex ) return null;
+ if( hex.length === 3 ) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
+ return hex.length === 6 ? hex : null;
+ };
+
+ var hsb2rgb = function(hsb) {
+ var rgb = {};
+ var h = Math.round(hsb.h);
+ var s = Math.round(hsb.s*255/100);
+ var v = Math.round(hsb.b*255/100);
+ if(s === 0) {
+ rgb.r = rgb.g = rgb.b = v;
+ } else {
+ var t1 = v;
+ var t2 = (255 - s) * v / 255;
+ var t3 = (t1 - t2) * (h % 60) / 60;
+ if( h === 360 ) h = 0;
+ if( h < 60 ) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; }
+ else if( h < 120 ) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; }
+ else if( h < 180 ) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; }
+ else if( h < 240 ) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; }
+ else if( h < 300 ) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; }
+ else if( h < 360 ) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; }
+ else { rgb.r = 0; rgb.g = 0; rgb.b = 0; }
+ }
+ return {
+ r: Math.round(rgb.r),
+ g: Math.round(rgb.g),
+ b: Math.round(rgb.b)
+ };
+ };
+
+ var rgb2hex = function(rgb) {
+ var hex = [
+ rgb.r.toString(16),
+ rgb.g.toString(16),
+ rgb.b.toString(16)
+ ];
+ $.each(hex, function(nr, val) {
+ if (val.length === 1) hex[nr] = '0' + val;
+ });
+ return hex.join('');
+ };
+
+ var hex2rgb = function(hex) {
+ hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
+
+ return {
+ r: hex >> 16,
+ g: (hex & 0x00FF00) >> 8,
+ b: (hex & 0x0000FF)
+ };
+ };
+
+ var rgb2hsb = function(rgb) {
+ var hsb = { h: 0, s: 0, b: 0 };
+ var min = Math.min(rgb.r, rgb.g, rgb.b);
+ var max = Math.max(rgb.r, rgb.g, rgb.b);
+ var delta = max - min;
+ hsb.b = max;
+ hsb.s = max !== 0 ? 255 * delta / max : 0;
+ if( hsb.s !== 0 ) {
+ if( rgb.r === max ) {
+ hsb.h = (rgb.g - rgb.b) / delta;
+ } else if( rgb.g === max ) {
+ hsb.h = 2 + (rgb.b - rgb.r) / delta;
+ } else {
+ hsb.h = 4 + (rgb.r - rgb.g) / delta;
+ }
+ } else {
+ hsb.h = -1;
+ }
+ hsb.h *= 60;
+ if( hsb.h < 0 ) {
+ hsb.h += 360;
+ }
+ hsb.s *= 100/255;
+ hsb.b *= 100/255;
+ return hsb;
+ };
+
+ var hex2hsb = function(hex) {
+ var hsb = rgb2hsb(hex2rgb(hex));
+ // Zero out hue marker for black, white, and grays (saturation === 0)
+ if( hsb.s === 0 ) hsb.h = 360;
+ return hsb;
+ };
+
+ var hsb2hex = function(hsb) {
+ return rgb2hex(hsb2rgb(hsb));
+ };
+
+
+ // Handle calls to $([selector]).miniColors()
+ switch(o) {
+
+ case 'readonly':
+
+ $(this).each( function() {
+ if( !$(this).hasClass('miniColors') ) return;
+ $(this).prop('readonly', data);
+ });
+
+ return $(this);
+
+ case 'disabled':
+
+ $(this).each( function() {
+ if( !$(this).hasClass('miniColors') ) return;
+ if( data ) {
+ disable($(this));
+ } else {
+ enable($(this));
+ }
+ });
+
+ return $(this);
+
+ case 'value':
+
+ // Getter
+ if( data === undefined ) {
+ if( !$(this).hasClass('miniColors') ) return;
+ var input = $(this),
+ hex = expandHex(input.val());
+ return hex ? '#' + convertCase(hex, input.data('letterCase')) : null;
+ }
+
+ // Setter
+ $(this).each( function() {
+ if( !$(this).hasClass('miniColors') ) return;
+ $(this).val(data);
+ setColorFromInput($(this));
+ });
+
+ return $(this);
+
+ case 'destroy':
+
+ $(this).each( function() {
+ if( !$(this).hasClass('miniColors') ) return;
+ destroy($(this));
+ });
+
+ return $(this);
+
+ default:
+
+ if( !o ) o = {};
+
+ $(this).each( function() {
+
+ // Must be called on an input element
+ if( $(this)[0].tagName.toLowerCase() !== 'input' ) return;
+
+ // If a trigger is present, the control was already created
+ if( $(this).data('trigger') ) return;
+
+ // Create the control
+ create($(this), o, data);
+
+ });
+
+ return $(this);
+
+ }
+
+ }
+
+ });
+
+})(jQuery); \ No newline at end of file
diff --git a/3rdparty/miniColors/js/jquery.miniColors.min.js b/3rdparty/miniColors/js/jquery.miniColors.min.js
new file mode 100755
index 00000000000..c00e0ace6b5
--- /dev/null
+++ b/3rdparty/miniColors/js/jquery.miniColors.min.js
@@ -0,0 +1,9 @@
+/*
+ * jQuery miniColors: A small color selector
+ *
+ * Copyright 2011 Cory LaViska for A Beautiful Site, LLC. (http://abeautifulsite.net/)
+ *
+ * Dual licensed under the MIT or GPL Version 2 licenses
+ *
+*/
+if(jQuery)(function($){$.extend($.fn,{miniColors:function(o,data){var create=function(input,o,data){var color=expandHex(input.val());if(!color)color='ffffff';var hsb=hex2hsb(color);var trigger=$('<a class="miniColors-trigger" style="background-color: #'+color+'" href="#"></a>');trigger.insertAfter(input);input.addClass('miniColors').data('original-maxlength',input.attr('maxlength')||null).data('original-autocomplete',input.attr('autocomplete')||null).data('letterCase','uppercase').data('trigger',trigger).data('hsb',hsb).data('change',o.change?o.change:null).data('close',o.close?o.close:null).data('open',o.open?o.open:null).attr('maxlength',7).attr('autocomplete','off').val('#'+convertCase(color,o.letterCase));if(o.readonly)input.prop('readonly',true);if(o.disabled)disable(input);trigger.bind('click.miniColors',function(event){event.preventDefault();if(input.val()==='')input.val('#');show(input)});input.bind('focus.miniColors',function(event){if(input.val()==='')input.val('#');show(input)});input.bind('blur.miniColors',function(event){var hex=expandHex(hsb2hex(input.data('hsb')));input.val(hex?'#'+convertCase(hex,input.data('letterCase')):'')});input.bind('keydown.miniColors',function(event){if(event.keyCode===9)hide(input)});input.bind('keyup.miniColors',function(event){setColorFromInput(input)});input.bind('paste.miniColors',function(event){setTimeout(function(){setColorFromInput(input)},5)})};var destroy=function(input){hide();input=$(input);input.data('trigger').remove();input.attr('autocomplete',input.data('original-autocomplete')).attr('maxlength',input.data('original-maxlength')).removeData().removeClass('miniColors').unbind('.miniColors');$(document).unbind('.miniColors')};var enable=function(input){input.prop('disabled',false).data('trigger').css('opacity',1)};var disable=function(input){hide(input);input.prop('disabled',true).data('trigger').css('opacity',0.5)};var show=function(input){if(input.prop('disabled'))return false;hide();var selector=$('<div class="miniColors-selector"></div>');selector.append('<div class="miniColors-colors" style="background-color: #FFF;"><div class="miniColors-colorPicker"><div class="miniColors-colorPicker-inner"></div></div>').append('<div class="miniColors-hues"><div class="miniColors-huePicker"></div></div>').css({top:input.is(':visible')?input.offset().top+input.outerHeight():input.data('trigger').offset().top+input.data('trigger').outerHeight(),left:input.is(':visible')?input.offset().left:input.data('trigger').offset().left,display:'none'}).addClass(input.attr('class'));var hsb=input.data('hsb');selector.find('.miniColors-colors').css('backgroundColor','#'+hsb2hex({h:hsb.h,s:100,b:100}));var colorPosition=input.data('colorPosition');if(!colorPosition)colorPosition=getColorPositionFromHSB(hsb);selector.find('.miniColors-colorPicker').css('top',colorPosition.y+'px').css('left',colorPosition.x+'px');var huePosition=input.data('huePosition');if(!huePosition)huePosition=getHuePositionFromHSB(hsb);selector.find('.miniColors-huePicker').css('top',huePosition.y+'px');input.data('selector',selector).data('huePicker',selector.find('.miniColors-huePicker')).data('colorPicker',selector.find('.miniColors-colorPicker')).data('mousebutton',0);$('BODY').append(selector);selector.fadeIn(100);selector.bind('selectstart',function(){return false});$(document).bind('mousedown.miniColors touchstart.miniColors',function(event){input.data('mousebutton',1);var testSubject=$(event.target).parents().andSelf();if(testSubject.hasClass('miniColors-colors')){event.preventDefault();input.data('moving','colors');moveColor(input,event)}if(testSubject.hasClass('miniColors-hues')){event.preventDefault();input.data('moving','hues');moveHue(input,event)}if(testSubject.hasClass('miniColors-selector')){event.preventDefault();return}if(testSubject.hasClass('miniColors'))return;hide(input)});$(document).bind('mouseup.miniColors touchend.miniColors',function(event){event.preventDefault();input.data('mousebutton',0).removeData('moving')}).bind('mousemove.miniColors touchmove.miniColors',function(event){event.preventDefault();if(input.data('mousebutton')===1){if(input.data('moving')==='colors')moveColor(input,event);if(input.data('moving')==='hues')moveHue(input,event)}});if(input.data('open')){input.data('open').call(input.get(0),'#'+hsb2hex(hsb),hsb2rgb(hsb))}};var hide=function(input){if(!input)input='.miniColors';$(input).each(function(){var selector=$(this).data('selector');$(this).removeData('selector');$(selector).fadeOut(100,function(){if(input.data('close')){var hsb=input.data('hsb'),hex=hsb2hex(hsb);input.data('close').call(input.get(0),'#'+hex,hsb2rgb(hsb))}$(this).remove()})});$(document).unbind('.miniColors')};var moveColor=function(input,event){var colorPicker=input.data('colorPicker');colorPicker.hide();var position={x:event.pageX,y:event.pageY};if(event.originalEvent.changedTouches){position.x=event.originalEvent.changedTouches[0].pageX;position.y=event.originalEvent.changedTouches[0].pageY}position.x=position.x-input.data('selector').find('.miniColors-colors').offset().left-5;position.y=position.y-input.data('selector').find('.miniColors-colors').offset().top-5;if(position.x<=-5)position.x=-5;if(position.x>=144)position.x=144;if(position.y<=-5)position.y=-5;if(position.y>=144)position.y=144;input.data('colorPosition',position);colorPicker.css('left',position.x).css('top',position.y).show();var s=Math.round((position.x+5)*0.67);if(s<0)s=0;if(s>100)s=100;var b=100-Math.round((position.y+5)*0.67);if(b<0)b=0;if(b>100)b=100;var hsb=input.data('hsb');hsb.s=s;hsb.b=b;setColor(input,hsb,true)};var moveHue=function(input,event){var huePicker=input.data('huePicker');huePicker.hide();var position={y:event.pageY};if(event.originalEvent.changedTouches){position.y=event.originalEvent.changedTouches[0].pageY}position.y=position.y-input.data('selector').find('.miniColors-colors').offset().top-1;if(position.y<=-1)position.y=-1;if(position.y>=149)position.y=149;input.data('huePosition',position);huePicker.css('top',position.y).show();var h=Math.round((150-position.y-1)*2.4);if(h<0)h=0;if(h>360)h=360;var hsb=input.data('hsb');hsb.h=h;setColor(input,hsb,true)};var setColor=function(input,hsb,updateInput){input.data('hsb',hsb);var hex=hsb2hex(hsb);if(updateInput)input.val('#'+convertCase(hex,input.data('letterCase')));input.data('trigger').css('backgroundColor','#'+hex);if(input.data('selector'))input.data('selector').find('.miniColors-colors').css('backgroundColor','#'+hsb2hex({h:hsb.h,s:100,b:100}));if(input.data('change')){if(hex===input.data('lastChange'))return;input.data('change').call(input.get(0),'#'+hex,hsb2rgb(hsb));input.data('lastChange',hex)}};var setColorFromInput=function(input){input.val('#'+cleanHex(input.val()));var hex=expandHex(input.val());if(!hex)return false;var hsb=hex2hsb(hex);var currentHSB=input.data('hsb');if(hsb.h===currentHSB.h&&hsb.s===currentHSB.s&&hsb.b===currentHSB.b)return true;var colorPosition=getColorPositionFromHSB(hsb);var colorPicker=$(input.data('colorPicker'));colorPicker.css('top',colorPosition.y+'px').css('left',colorPosition.x+'px');input.data('colorPosition',colorPosition);var huePosition=getHuePositionFromHSB(hsb);var huePicker=$(input.data('huePicker'));huePicker.css('top',huePosition.y+'px');input.data('huePosition',huePosition);setColor(input,hsb);return true};var convertCase=function(string,letterCase){if(letterCase==='lowercase')return string.toLowerCase();if(letterCase==='uppercase')return string.toUpperCase();return string};var getColorPositionFromHSB=function(hsb){var x=Math.ceil(hsb.s/0.67);if(x<0)x=0;if(x>150)x=150;var y=150-Math.ceil(hsb.b/0.67);if(y<0)y=0;if(y>150)y=150;return{x:x-5,y:y-5}};var getHuePositionFromHSB=function(hsb){var y=150-(hsb.h/2.4);if(y<0)h=0;if(y>150)h=150;return{y:y-1}};var cleanHex=function(hex){return hex.replace(/[^A-F0-9]/ig,'')};var expandHex=function(hex){hex=cleanHex(hex);if(!hex)return null;if(hex.length===3)hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];return hex.length===6?hex:null};var hsb2rgb=function(hsb){var rgb={};var h=Math.round(hsb.h);var s=Math.round(hsb.s*255/100);var v=Math.round(hsb.b*255/100);if(s===0){rgb.r=rgb.g=rgb.b=v}else{var t1=v;var t2=(255-s)*v/255;var t3=(t1-t2)*(h%60)/60;if(h===360)h=0;if(h<60){rgb.r=t1;rgb.b=t2;rgb.g=t2+t3}else if(h<120){rgb.g=t1;rgb.b=t2;rgb.r=t1-t3}else if(h<180){rgb.g=t1;rgb.r=t2;rgb.b=t2+t3}else if(h<240){rgb.b=t1;rgb.r=t2;rgb.g=t1-t3}else if(h<300){rgb.b=t1;rgb.g=t2;rgb.r=t2+t3}else if(h<360){rgb.r=t1;rgb.g=t2;rgb.b=t1-t3}else{rgb.r=0;rgb.g=0;rgb.b=0}}return{r:Math.round(rgb.r),g:Math.round(rgb.g),b:Math.round(rgb.b)}};var rgb2hex=function(rgb){var hex=[rgb.r.toString(16),rgb.g.toString(16),rgb.b.toString(16)];$.each(hex,function(nr,val){if(val.length===1)hex[nr]='0'+val});return hex.join('')};var hex2rgb=function(hex){hex=parseInt(((hex.indexOf('#')>-1)?hex.substring(1):hex),16);return{r:hex>>16,g:(hex&0x00FF00)>>8,b:(hex&0x0000FF)}};var rgb2hsb=function(rgb){var hsb={h:0,s:0,b:0};var min=Math.min(rgb.r,rgb.g,rgb.b);var max=Math.max(rgb.r,rgb.g,rgb.b);var delta=max-min;hsb.b=max;hsb.s=max!==0?255*delta/max:0;if(hsb.s!==0){if(rgb.r===max){hsb.h=(rgb.g-rgb.b)/delta}else if(rgb.g===max){hsb.h=2+(rgb.b-rgb.r)/delta}else{hsb.h=4+(rgb.r-rgb.g)/delta}}else{hsb.h=-1}hsb.h*=60;if(hsb.h<0){hsb.h+=360}hsb.s*=100/255;hsb.b*=100/255;return hsb};var hex2hsb=function(hex){var hsb=rgb2hsb(hex2rgb(hex));if(hsb.s===0)hsb.h=360;return hsb};var hsb2hex=function(hsb){return rgb2hex(hsb2rgb(hsb))};switch(o){case'readonly':$(this).each(function(){if(!$(this).hasClass('miniColors'))return;$(this).prop('readonly',data)});return $(this);case'disabled':$(this).each(function(){if(!$(this).hasClass('miniColors'))return;if(data){disable($(this))}else{enable($(this))}});return $(this);case'value':if(data===undefined){if(!$(this).hasClass('miniColors'))return;var input=$(this),hex=expandHex(input.val());return hex?'#'+convertCase(hex,input.data('letterCase')):null}$(this).each(function(){if(!$(this).hasClass('miniColors'))return;$(this).val(data);setColorFromInput($(this))});return $(this);case'destroy':$(this).each(function(){if(!$(this).hasClass('miniColors'))return;destroy($(this))});return $(this);default:if(!o)o={};$(this).each(function(){if($(this)[0].tagName.toLowerCase()!=='input')return;if($(this).data('trigger'))return;create($(this),o,data)});return $(this)}}})})(jQuery); \ No newline at end of file
diff --git a/apps/user_openid/class.openid.v3.php b/3rdparty/openid/class.openid.v3.php
index eeb31986659..eeb31986659 100644
--- a/apps/user_openid/class.openid.v3.php
+++ b/3rdparty/openid/class.openid.v3.php
diff --git a/apps/user_openid/phpmyid.php b/3rdparty/openid/phpmyid.php
index 13fd31c47ca..13fd31c47ca 100644
--- a/apps/user_openid/phpmyid.php
+++ b/3rdparty/openid/phpmyid.php
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/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/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 8d881498768..4c6c8bf3d93 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -12,10 +12,42 @@ String.prototype.strip_tags = function(){
Contacts={
UI:{
+ /**
+ * Arguments:
+ * message: The text message to show. The only mandatory parameter.
+ * timeout: The timeout in seconds before the notification disappears. Default 10.
+ * timeouthandler: A function to run on timeout.
+ * clickhandler: A function to run on click. If a timeouthandler is given it will be cancelled.
+ * data: An object that will be passed as argument to the timeouthandler and clickhandler functions.
+ */
notify:function(params) {
- $('#notification').text(params.message);
- $('#notification').fadeIn();
- setTimeout(function() {$('#notification').fadeOut();}, 10000);
+ 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() {
+ self.notifier.fadeOut();
+ if(params.timeouthandler && $.isFunction(params.timeouthandler)) {
+ 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) {
+ self.notifier.data(dataid, params.data);
+ }
+ if(params.clickhandler && $.isFunction(params.clickhandler)) {
+ self.notifier.on('click', function() {
+ clearTimeout(timer);
+ self.notifier.off('click');
+ params.clickhandler(self.notifier.data(dataid));
+ self.notifier.removeData(dataid);
+ });
+ }
},
notImplemented:function() {
OC.dialogs.alert(t('contacts', 'Sorry, this functionality has not been implemented yet'), t('contacts', 'Not implemented'));
@@ -96,7 +128,7 @@ Contacts={
$('.addresscard,.propertylist li,.propertycontainer').hover(
function () {
$(this).find('.globe,.mail,.delete,.edit').animate({ opacity: 1.0 }, 200, function() {});
- },
+ },
function () {
$(this).find('.globe,.mail,.delete,.edit').animate({ opacity: 0.1 }, 200, function() {});
}
@@ -107,7 +139,7 @@ Contacts={
obj.tipsy('hide');
Contacts.UI.Card.deleteProperty(obj, 'single');
}
-
+
var goToUrl = function(obj) {
var url = Contacts.UI.propertyContainerFor(obj).find('#url').val();
if(url != '') {
@@ -115,7 +147,7 @@ Contacts={
newWindow.focus();
}
}
-
+
$('#identityprops a.delete').click( function() { deleteItem($(this)) });
$('#identityprops a.delete').keydown( function() { deleteItem($(this)) });
$('#categories_value a.edit').click( function() { $(this).tipsy('hide');OCCategories.edit(); } );
@@ -140,7 +172,7 @@ Contacts={
});
$('#edit_name').click(function(){Contacts.UI.Card.editName()});
$('#edit_name').keydown(function(){Contacts.UI.Card.editName()});
-
+
$('#phototools li a').click(function() {
$(this).tipsy('hide');
});
@@ -167,13 +199,13 @@ Contacts={
OC.dialogs.filepicker(t('contacts', 'Select photo'), Contacts.UI.Card.cloudPhotoSelected, false, 'image', true);
});
/* Initialize the photo edit dialog */
- $('#edit_photo_dialog').dialog({
+ $('#edit_photo_dialog').dialog({
autoOpen: false, modal: true, height: 'auto', width: 'auto'
});
$('#edit_photo_dialog' ).dialog( 'option', 'buttons', [
{
text: "Ok",
- click: function() {
+ click: function() {
Contacts.UI.Card.savePhoto(this);
$(this).dialog('close');
}
@@ -183,31 +215,27 @@ Contacts={
click: function() { $(this).dialog('close'); }
}
] );
-
+
// Name has changed. Update it and reorder.
$('#fn').change(function(){
var name = $('#fn').val().strip_tags();
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);
});
- $('#contacts_deletecard').click( function() { Contacts.UI.Card.doDelete();return false;} );
- $('#contacts_deletecard').keydown( function(event) {
+ $('#contacts_deletecard').click( function() { Contacts.UI.Card.delayedDelete();return false;} );
+ $('#contacts_deletecard').keydown( function(event) {
if(event.which == 13 || event.which == 32) {
- Contacts.UI.Card.doDelete();
+ Contacts.UI.Card.delayedDelete();
}
return false;
});
$('#contacts_downloadcard').click( function() { Contacts.UI.Card.doExport();return false;} );
- $('#contacts_downloadcard').keydown( function(event) {
+ $('#contacts_downloadcard').keydown( function(event) {
if(event.which == 13 || event.which == 32) {
Contacts.UI.Card.doExport();
}
@@ -222,12 +250,12 @@ Contacts={
$('#contacts_details_photo_wrapper').bind('dragover',function(event){
$(event.target).addClass('droppable');
event.stopPropagation();
- event.preventDefault();
+ event.preventDefault();
});
$('#contacts_details_photo_wrapper').bind('dragleave',function(event){
$(event.target).removeClass('droppable');
//event.stopPropagation();
- //event.preventDefault();
+ //event.preventDefault();
});
$('#contacts_details_photo_wrapper').bind('drop',function(event){
event.stopPropagation();
@@ -267,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');
@@ -293,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';
}
@@ -313,10 +332,10 @@ Contacts={
if($('.contacts li').length > 0) {
$.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){
if(jsondata.status == 'success'){
- if(bookid == 'unknown') {
- bookid = jsondata.data.addressbookid;
+ if(bookid == 'unknown') {
+ bookid = jsondata.data.addressbookid;
var contact = Contacts.UI.Contacts.insertContact({
- contactlist:$('#contacts ul[data-id="'+bookid+'"]'),
+ contactlist:$('#contacts ul[data-id="'+bookid+'"]'),
data:jsondata.data
});
}
@@ -330,7 +349,7 @@ Contacts={
});
}
}
-
+
// Make sure proper DOM is loaded.
if(!$('#card').length && newid) {
console.log('Loading card DOM');
@@ -384,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');
@@ -415,7 +422,7 @@ Contacts={
}
});
}
-
+
if(!$('#card').length) {
console.log('Loading card DOM');
$.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{'requesttoken': requesttoken},function(jsondata){
@@ -432,47 +439,63 @@ Contacts={
localAddcontact(n, fn, aid, isnew);
}
},
- doDelete:function() {
+ delayedDelete:function() {
+ /* TODO:
+ $(window).unload(function() {
+ deleteFilesInQueue();
+ });
+ */
$('#contacts_deletecard').tipsy('hide');
- OC.dialogs.confirm(t('contacts', 'Are you sure you want to delete this contact?'), t('contacts', 'Warning'), function(answer) {
- if(answer == true) {
- $.post(OC.filePath('contacts', 'ajax', 'deletecard.php'),{'id':Contacts.UI.Card.id},function(jsondata){
- if(jsondata.status == 'success'){
- var newid = '', bookid;
- var curlistitem = $('#contacts li[data-id="'+jsondata.data.id+'"]');
- var newlistitem = curlistitem.prev('li');
- if(!newlistitem) {
- newlistitem = curlistitem.next('li');
- }
- curlistitem.remove();
- if($(newlistitem).is('li')) {
- 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;
-
- if($('.contacts li').length > 0) { // Load first in list.
- 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);
- }
- else{
- OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
- }
- });
- }
- }
- else{
- OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
- }
- });
+ var newid = '', bookid;
+ var curlistitem = Contacts.UI.Contacts.getContact(this.id);
+ curlistitem.removeClass('active');
+ var newlistitem = curlistitem.prev('li');
+ if(!newlistitem) {
+ newlistitem = curlistitem.next('li');
+ }
+ curlistitem.detach();
+ if($(newlistitem).is('li')) {
+ newid = newlistitem.data('id');
+ bookid = newlistitem.data('bookid');
+ }
+ $('#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) {
+ 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').html(jsondata.data.page).removeData('id');
+ }
+ else{
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
+ });
+ }
+ Contacts.UI.notify({
+ data:curlistitem,
+ message:t('contacts','Click to undo deletion of "') + curlistitem.find('a').text() + '"',
+ timeouthandler:function(contact) {
+ Contacts.UI.Card.doDelete(contact.data('id'));
+ delete contact;
+ },
+ clickhandler:function(contact) {
+ Contacts.UI.Contacts.insertContact({contact:contact});
+ Contacts.UI.notify({message:t('contacts', 'Cancelled deletion of: "') + curlistitem.find('a').text() + '"'});
+ }
+ });
+ },
+ doDelete:function(id) {
+ $.post(OC.filePath('contacts', 'ajax', 'deletecard.php'),{'id':id},function(jsondata) {
+ if(jsondata.status == 'error'){
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
return false;
@@ -489,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();
}
},
@@ -524,15 +548,16 @@ Contacts={
$('#contacts_propertymenu_dropdown a[data-type="'+propname+'"]').parent().hide();
var property = this.data[propname][0];
var value = property['value'], checksum = property['checksum'];
-
+
if(propname == 'BDAY') {
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();
}
@@ -547,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'];
}
@@ -589,7 +618,7 @@ Contacts={
$.each(names, function(key, value) {
$('#fn_select')
.append($('<option></option>')
- .text(value));
+ .text(value));
});
$('#fn_select').combobox('value', this.fn);
$('#contact_identity').find('*[data-element="N"]').data('checksum', this.data.N[0]['checksum']);
@@ -732,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) {
@@ -797,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);
@@ -825,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,
@@ -840,7 +860,7 @@ Contacts={
title: t('contacts', 'Edit name'),
height: 'auto', width: 'auto',
buttons: {
- 'Ok':function() {
+ 'Ok':function() {
Contacts.UI.Card.saveName(this);
$(this).dialog('close');
},
@@ -891,9 +911,9 @@ Contacts={
$.each(names, function(key, value) {
$('#fn_select')
.append($('<option></option>')
- .text(value));
+ .text(value));
});
-
+
if(this.id == '') {
var aid = $(dlg).find('#aid').val();
Contacts.UI.Card.add(n.join(';'), $('#short').text(), aid);
@@ -904,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) {
@@ -919,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) {
@@ -928,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']) {
@@ -937,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();
}
@@ -957,7 +978,7 @@ Contacts={
container = $('#addressdisplay dl').last();
container.removeClass('template').addClass('propertycontainer');
} else {
- params['checksum'] = Contacts.UI.checksumFor(obj);
+ params['checksum'] = Contacts.UI.checksumFor(obj);
}
/* Initialize the address edit dialog */
if($('#edit_address_dialog').dialog('isOpen') == true){
@@ -987,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({
@@ -1028,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",
@@ -1079,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) {
@@ -1108,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) {
@@ -1135,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){
@@ -1173,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
- $(t('contacts','something went wrong.')).insertAfter($('#phototools'));
+ 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){
@@ -1248,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() {
@@ -1287,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');
@@ -1324,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();
}
@@ -1430,7 +1450,7 @@ Contacts={
var displayname = $("#displayname_"+bookid).val().trim();
var active = $("#edit_active_"+bookid+":checked").length;
var description = $("#description_"+bookid).val();
-
+
if(displayname.length == 0) {
OC.dialogs.alert(t('contacts', 'Displayname cannot be empty.'), t('contacts', 'Error'));
return false;
@@ -1456,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')) {
@@ -1473,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'));
@@ -1498,13 +1527,24 @@ Contacts={
alert('Dropping address books not implemented yet');
},
/**
- * @params params An object with the propeties 'contactlist':a jquery object of the ul to insert into,
- * 'contacts':a jquery object of all items in the list and either 'data': an object with the properties
+ * @params params An object with the properties 'contactlist':a jquery object of the ul to insert into,
+ * 'contacts':a jquery object of all items in the list and either 'data': an object with the properties
* id, addressbookid and displayname or 'contact': a listitem to be inserted directly.
- * If 'contacts' is defined the new contact will be inserted alphabetically into the list, otherwise
- * it will be appended.
+ * 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.
+ 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) {
+ 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
? $('<li data-id="'+params.data.id+'" data-bookid="'+params.data.addressbookid+'" role="button"><a href="'+OC.linkTo('contacts', 'index.php')+'&id='+params.data.id+'" style="background: url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+params.data.id+') no-repeat scroll 0% 0% transparent;">'+params.data.displayname+'</a></li>')
: params.contact;
@@ -1522,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 = {}; }
@@ -1545,7 +1601,7 @@ Contacts={
$.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),opts,function(jsondata){
if(jsondata.status == 'success'){
var books = jsondata.data.entries;
- $.each(books, function(b, book) {
+ $.each(books, function(b, book) {
if($('#contacts h3[data-id="'+b+'"]').length == 0) {
firstrun = true;
if($('#contacts h3').length == 0) {
@@ -1564,7 +1620,7 @@ Contacts={
if(!added) {
$('#contacts').append(item);
}
-
+
}
}
$('#contacts h3[data-id="'+b+'"]').on('click', function(event) {
@@ -1627,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');
}
}
}
@@ -1641,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);
- $('#contacts_newcontact').click(Contacts.UI.Card.editNew);
- $('#contacts_newcontact').keydown(Contacts.UI.Card.editNew);
-
- // Load a contact.
+ $(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;
+ }
+
+ });
+
+ // 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();
@@ -1722,7 +1845,7 @@ $(document).ready(function(){
}
}
};
-
+
fileUpload.onprogress = function(e){
if (e.lengthComputable){
var _progress = Math.round((e.loaded * 100) / e.total);
@@ -1752,7 +1875,7 @@ $(document).ready(function(){
$(function() {
var uploadingFiles = {}, numfiles = 0, uploadedfiles = 0, retries = 0;
var aid;
-
+
$('#import_upload_start').fileupload({
dropZone: $('#contacts'), // restrict dropZone to contacts list.
acceptFileTypes: /^text\/(directory|vcard|x-vcard)$/i,
@@ -1886,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;
@@ -1914,7 +2038,7 @@ $(document).ready(function(){
$(this).dialog('close');
}
},
- 'Cancel':function() {
+ 'Cancel':function() {
$(this).dialog('close');
numfiles = uploadedfiles = retries = aid = 0;
uploadingFiles = {};
@@ -1941,11 +2065,11 @@ $(document).ready(function(){
}
if(data.dataType != 'iframe ') {
$('#upload input.stop').hide();
- }
+ }
}
})
});
-
+
Contacts.UI.loadHandlers();
Contacts.UI.Contacts.update({cid:id});
});
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/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/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/appinfo/app.php b/apps/user_openid/appinfo/app.php
index fe57b189fac..a5fb6a0f45e 100644
--- a/apps/user_openid/appinfo/app.php
+++ b/apps/user_openid/appinfo/app.php
@@ -19,7 +19,7 @@ OCP\Util::addHeader('link',array('rel'=>'openid.delegate', 'href'=>OCP\Util::lin
OCP\App::registerPersonal('user_openid','settings');
-require_once 'apps/user_openid/user_openid.php';
+require_once 'openid/user_openid.php';
//active the openid backend
OC_User::useBackend('openid');
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
diff --git a/core/css/styles.css b/core/css/styles.css
index 338518e5b2f..b818caa279f 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -139,6 +139,8 @@ li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ff
a.bookmarklet { background-color: #ddd; border:1px solid #ccc; padding: 5px;padding-top: 0px;padding-bottom: 2px; text-decoration: none; margin-top: 5px }
+.exception{color: #000000;}
+.exception textarea{width:95%;height: 200px;background:#ffe;border:0;}
/* ---- DIALOGS ---- */
#dirtree {width: 100%;}
diff --git a/core/js/eventsource.js b/core/js/eventsource.js
index 08259e02cae..e3ad7e3a671 100644
--- a/core/js/eventsource.js
+++ b/core/js/eventsource.js
@@ -40,6 +40,7 @@ OC.EventSource=function(src,data){
dataStr+=name+'='+encodeURIComponent(data[name])+'&';
}
}
+ dataStr+='requesttoken='+OC.EventSource.requesttoken;
if(!this.useFallBack && typeof EventSource !='undefined'){
this.source=new EventSource(src+'?'+dataStr);
this.source.onmessage=function(e){
diff --git a/core/templates/exception.php b/core/templates/exception.php
new file mode 100644
index 00000000000..7f58ce252cf
--- /dev/null
+++ b/core/templates/exception.php
@@ -0,0 +1,30 @@
+<ul>
+ <li class='error'>
+ <details>
+ <summary class="error">We're sorry, but something went terribly wrong.<br></summary>
+ <p class="exception">
+ <?php
+ if($_['showsysinfo'] == true){
+ echo 'If you would like to support ownCloud\'s developers and report this error in our <a href="http://bugs.owncloud.org">Bugtracker</a>, please copy the following informations into the description. <br><br><textarea readonly>';
+ echo 'Message: ' . $_['message'] . "\n";
+ echo 'Error Code: ' . $_['code'] . "\n";
+ echo 'File: ' . $_['file'] . "\n";
+ echo 'Line: ' . $_['line'] . "\n\n";
+ echo 'PHP: ' . $_['sysinfo']['phpversion'] . "\n";
+ echo 'OS: ' . $_['sysinfo']['os'] . "\n";
+ echo 'OS Release: ' . $_['sysinfo']['osrelease'] . "\n";
+ echo 'OS Arch.: ' . $_['sysinfo']['osarchitecture'] . "\n";
+ echo 'PHP-Server-Interface: ' . $_['sysinfo']['phpserverinterface'] . "\n";
+ echo 'Protocol: ' . $_['sysinfo']['serverprotocol'] . "\n";
+ echo 'HTTPS: ' . $_['sysinfo']['https'] . "\n";
+ echo 'Request Method: ' . $_['sysinfo']['requestmethod'] . "\n";
+ echo 'Database: ' . $_['sysinfo']['database'] . "\n";
+ echo '</textarea>';
+ }else{
+ echo 'Your administrator has disabled systeminformations.';
+ }
+ ?>
+ </p>
+ </details>
+ </li>
+</ul> \ No newline at end of file
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index 7e98fdedc2d..dc303ffc1a7 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -33,6 +33,7 @@
<script type="text/javascript">
$(function() {
requesttoken = '<?php echo $_['requesttoken']; ?>';
+ OC.EventSource.requesttoken=requesttoken;
$(document).bind('ajaxSend', function(elm, xhr, s){
if(requesttoken) {
xhr.setRequestHeader('requesttoken', requesttoken);
diff --git a/lib/app.php b/lib/app.php
index 2b975de9ef0..56132c08671 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -195,7 +195,7 @@ class OC_App{
// check if the app is compatible with this version of ownCloud
$info=OC_App::getAppInfo($app);
$version=OC_Util::getVersion();
- if(!isset($info['require']) or ($version[0]>$info['require'])){
+ if(!isset($info['require']) or ($version[0]>$info['require'])){
OC_Log::write('core','App "'.$info['name'].'" can\'t be installed because it is not compatible with this version of ownCloud',OC_Log::ERROR);
return false;
}else{
@@ -331,8 +331,8 @@ class OC_App{
}
/**
- * Get the path where to install apps
- */
+ * Get the path where to install apps
+ */
public static function getInstallPath() {
if(OC_Config::getValue('appstoreenabled', true)==false) {
return false;
diff --git a/lib/cache.php b/lib/cache.php
index 1f269174fad..55f189a5da8 100644
--- a/lib/cache.php
+++ b/lib/cache.php
@@ -7,48 +7,96 @@
*/
class OC_Cache {
+ /**
+ * @var OC_Cache $user_cache
+ */
static protected $user_cache;
+ /**
+ * @var OC_Cache $global_cache
+ */
static protected $global_cache;
+ /**
+ * @var OC_Cache $global_cache_fast
+ */
+ static protected $global_cache_fast;
+ /**
+ * @var OC_Cache $user_cache_fast
+ */
+ static protected $user_cache_fast;
+ static protected $isFast=null;
- static public function getGlobalCache() {
+ /**
+ * get the global cache
+ * @return OC_Cache
+ */
+ static public function getGlobalCache($fast=false) {
if (!self::$global_cache) {
- $fast_cache = null;
- if (!$fast_cache && function_exists('xcache_set')) {
- $fast_cache = new OC_Cache_XCache(true);
+ self::$global_cache_fast = null;
+ if (!self::$global_cache_fast && function_exists('xcache_set')) {
+ self::$global_cache_fast = new OC_Cache_XCache(true);
}
- if (!$fast_cache && function_exists('apc_store')) {
- $fast_cache = new OC_Cache_APC(true);
+ if (!self::$global_cache_fast && function_exists('apc_store')) {
+ self::$global_cache_fast = new OC_Cache_APC(true);
}
+
self::$global_cache = new OC_Cache_FileGlobal();
- if ($fast_cache) {
- self::$global_cache = new OC_Cache_Broker($fast_cache, self::$global_cache);
+ if (self::$global_cache_fast) {
+ self::$global_cache = new OC_Cache_Broker(self::$global_cache_fast, self::$global_cache);
+ }
+ }
+ if($fast){
+ if(self::$global_cache_fast){
+ return self::$global_cache_fast;
+ }else{
+ return false;
}
}
return self::$global_cache;
}
- static public function getUserCache() {
+ /**
+ * get the user cache
+ * @return OC_Cache
+ */
+ static public function getUserCache($fast=false) {
if (!self::$user_cache) {
- $fast_cache = null;
- if (!$fast_cache && function_exists('xcache_set')) {
- $fast_cache = new OC_Cache_XCache();
+ self::$user_cache_fast = null;
+ if (!self::$user_cache_fast && function_exists('xcache_set')) {
+ self::$user_cache_fast = new OC_Cache_XCache();
}
- if (!$fast_cache && function_exists('apc_store')) {
- $fast_cache = new OC_Cache_APC();
+ if (!self::$user_cache_fast && function_exists('apc_store')) {
+ self::$user_cache_fast = new OC_Cache_APC();
}
+
self::$user_cache = new OC_Cache_File();
- if ($fast_cache) {
- self::$user_cache = new OC_Cache_Broker($fast_cache, self::$user_cache);
+ if (self::$user_cache_fast) {
+ self::$user_cache = new OC_Cache_Broker(self::$user_cache_fast, self::$user_cache);
+ }
+ }
+
+ if($fast){
+ if(self::$user_cache_fast){
+ return self::$user_cache_fast;
+ }else{
+ return false;
}
}
return self::$user_cache;
}
+ /**
+ * get a value from the user cache
+ * @return mixed
+ */
static public function get($key) {
$user_cache = self::getUserCache();
return $user_cache->get($key);
}
+ /**
+ * set a value in the user cache
+ * @return bool
+ */
static public function set($key, $value, $ttl=0) {
if (empty($key)) {
return false;
@@ -57,19 +105,43 @@ class OC_Cache {
return $user_cache->set($key, $value, $ttl);
}
+ /**
+ * check if a value is set in the user cache
+ * @return bool
+ */
static public function hasKey($key) {
$user_cache = self::getUserCache();
return $user_cache->hasKey($key);
}
+ /**
+ * remove an item from the user cache
+ * @return bool
+ */
static public function remove($key) {
$user_cache = self::getUserCache();
return $user_cache->remove($key);
}
- static public function clear() {
+ /**
+ * clear the user cache of all entries starting with a prefix
+ * @param string prefix (optional)
+ * @return bool
+ */
+ static public function clear($prefix='') {
$user_cache = self::getUserCache();
- return $user_cache->clear();
+ return $user_cache->clear($prefix);
+ }
+
+ /**
+ * check if a fast memory based cache is available
+ * @return true
+ */
+ static public function isFast() {
+ if(is_null(self::$isFast)){
+ self::$isFast=function_exists('xcache_set') || function_exists('apc_store');
+ }
+ return self::$isFast;
}
}
diff --git a/lib/cache/apc.php b/lib/cache/apc.php
index 6cf47d0c158..c192fe2f196 100644
--- a/lib/cache/apc.php
+++ b/lib/cache/apc.php
@@ -43,14 +43,15 @@ class OC_Cache_APC {
return apc_delete($this->getNamespace().$key);
}
- public function clear(){
- $ns = $this->getNamespace();
+ public function clear($prefix=''){
+ $ns = $this->getNamespace().$prefix;
$cache = apc_cache_info('user');
foreach($cache['cache_list'] as $entry) {
if (strpos($entry['info'], $ns) === 0) {
apc_delete($entry['info']);
}
}
+ return true;
}
}
if(!function_exists('apc_exists')) {
diff --git a/lib/cache/broker.php b/lib/cache/broker.php
index 931d0dd407e..c2aceabaf53 100644
--- a/lib/cache/broker.php
+++ b/lib/cache/broker.php
@@ -46,8 +46,8 @@ class OC_Cache_Broker {
return $this->slow_cache->remove($key);
}
- public function clear(){
- $this->fast_cache->clear();
- $this->slow_cache->clear();
+ public function clear($prefix=''){
+ $this->fast_cache->clear($prefix);
+ $this->slow_cache->clear($prefix);
}
}
diff --git a/lib/cache/file.php b/lib/cache/file.php
index 0b7d3e30508..562c3d17167 100644
--- a/lib/cache/file.php
+++ b/lib/cache/file.php
@@ -62,15 +62,16 @@ class OC_Cache_File{
return $storage->unlink($key);
}
- public function clear(){
+ public function clear($prefix=''){
$storage = $this->getStorage();
if($storage and $storage->is_dir('/')){
$dh=$storage->opendir('/');
while($file=readdir($dh)){
- if($file!='.' and $file!='..'){
+ if($file!='.' and $file!='..' and ($prefix==='' || strpos($file, $prefix) === 0)){
$storage->unlink('/'.$file);
}
}
}
+ return true;
}
}
diff --git a/lib/cache/xcache.php b/lib/cache/xcache.php
index bd55cee8f6b..951f9b47545 100644
--- a/lib/cache/xcache.php
+++ b/lib/cache/xcache.php
@@ -43,7 +43,8 @@ class OC_Cache_XCache {
return xcache_unset($this->getNamespace().$key);
}
- public function clear(){
- return xcache_unset_by_prefix($this->getNamespace());
+ public function clear($prefix=''){
+ xcache_unset_by_prefix($this->getNamespace().$prefix);
+ return true;
}
}
diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php
index 3cb5412f09f..663970487fb 100644
--- a/lib/connector/sabre/node.php
+++ b/lib/connector/sabre/node.php
@@ -142,6 +142,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
public function updateProperties($properties) {
$existing = $this->getProperties(array());
foreach($properties as $propertyName => $propertyValue) {
+ $propertyName = preg_replace("/^{.*}/", "", $propertyName); // remove leading namespace from property name
// If it was null, we need to delete the property
if (is_null($propertyValue)) {
if(array_key_exists( $propertyName, $existing )){
diff --git a/lib/db.php b/lib/db.php
index 6f083d17cfb..6971fe4a583 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -368,9 +368,6 @@ class OC_DB {
if( $definition instanceof MDB2_Schema_Error ){
die( $definition->getMessage().': '.$definition->getUserInfo());
}
-// if(OC_Config::getValue('dbtype','sqlite')=='sqlite'){
-// $definition['overwrite']=true;//always overwrite for sqlite
-// }
$ret=self::$schema->createDatabase( $definition );
// Die in case something went wrong
@@ -527,8 +524,7 @@ class OC_DB {
* @brief replaces the owncloud tables with a new set
* @param $file string path to the MDB2 xml db export file
*/
- public static function replaceDB( $file ){
-
+ public static function replaceDB( $file ){
$apps = OC_App::getAllApps();
self::beginTransaction();
// Delete the old tables
diff --git a/lib/eventsource.php b/lib/eventsource.php
index 2a8c6b92902..95af2e471bc 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -42,6 +42,9 @@ class OC_EventSource{
}else{
header("Content-Type: text/event-stream");
}
+ if( !OC_Util::isCallRegistered()){
+ exit();
+ }
flush();
}
diff --git a/lib/exception.php b/lib/exception.php
new file mode 100644
index 00000000000..db516fc12d2
--- /dev/null
+++ b/lib/exception.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Georg Ehrke
+ * @copyright 2012 georg@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/>.
+ *
+ */
+class OC_Exception extends Exception{
+
+ function __construct($message = null, $code = 0, $file = null, $line = null){
+ parent::__construct($message, $code);
+ if(!is_null($file)){
+ $this->file = $file;
+ }
+ if(!is_null($line)){
+ $this->line = $line;
+ }
+ $this->writelog();
+ }
+
+ private function writelog(){
+ @OC_Log::write(OC_App::getCurrentApp(), $this->getMessage() . '-' . $this->getFile() . '-' . $this->getLine(), OC_Log::FATAL);
+ }
+
+ private function generatesysinfo(){
+ return array('phpversion' => PHP_VERSION,
+ 'os' => php_uname('s'),
+ 'osrelease' => php_uname('r'),
+ 'osarchitecture' => php_uname('m'),
+ 'phpserverinterface' => php_sapi_name(),
+ 'serverprotocol' => $_SERVER['SERVER_PROTOCOL'],
+ 'requestmethod' => $_SERVER['REQUEST_METHOD'],
+ 'https' => ($_SERVER['HTTPS']==''?'false':'true'),
+ 'database'=>(@OC_Config::getValue('dbtype')!=''?@OC_Config::getValue('dbtype'):'')
+ );
+ }
+
+ function __toString(){
+ $tmpl = new OC_Template('core', 'exception', 'guest');
+ $tmpl->assign('showsysinfo', true);
+ $tmpl->assign('message', $this->getMessage());
+ $tmpl->assign('code', $this->getCode());
+ $tmpl->assign('file', $this->getFile());
+ $tmpl->assign('line', $this->getLine());
+ $tmpl->assign('sysinfo', $this->generatesysinfo());
+ $tmpl->printPage();
+ }
+}
+
+function oc_exceptionhandler($exception){
+ switch($exception->getCode()){
+ case E_NOTICE:
+ case E_DEPRECATED:
+ case E_USER_NOTICE:
+ case E_USER_DEPRECATED:
+ break;
+ default:
+ throw new OC_Exception($exception->getMessage(), $exception->getCode(), $exception->getFile(), $exception->getLine());
+ break;
+ }
+ return true;
+}
+
+function oc_errorhandler($errno , $errstr , $errfile , $errline){
+ switch($errno){
+ case E_NOTICE:
+ case E_DEPRECATED:
+ case E_USER_NOTICE:
+ case E_USER_DEPRECATED:
+ break;
+ default:
+ throw new OC_Exception($errstr, $errno, $errfile, $errline);
+ break;
+ }
+ return true;
+}
+set_exception_handler('oc_exceptionhandler');
+set_error_handler('oc_errorhandler');
+error_reporting(E_ERROR | E_WARNING | E_PARSE); \ No newline at end of file
diff --git a/lib/filecache.php b/lib/filecache.php
index 4b1774925c3..22f7427ae42 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -98,6 +98,10 @@ class OC_FileCache{
if(OC_DB::isError($result)){
OC_Log::write('files','error while writing file('.$path.') to cache',OC_Log::ERROR);
}
+
+ if($cache=OC_Cache::getUserCache(true)){
+ $cache->remove('fileid/'.$path);//ensure we don't have -1 cached
+ }
}
/**
@@ -146,6 +150,11 @@ class OC_FileCache{
$query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=?, path_hash=? WHERE path_hash=?');
$query->execute(array($newParent,basename($newPath),$newPath,md5($newPath),md5($oldPath)));
+ if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$oldPath)){
+ $cache->set('fileid/'.$newPath,$cache->get('fileid/'.$oldPath));
+ $cache->remove('fileid/'.$oldPath);
+ }
+
$query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE path LIKE ?');
$oldLength=strlen($oldPath);
$updateQuery=OC_DB::prepare('UPDATE *PREFIX*fscache SET path=?, path_hash=? WHERE path_hash=?');
@@ -153,6 +162,11 @@ class OC_FileCache{
$old=$row['path'];
$new=$newPath.substr($old,$oldLength);
$updateQuery->execute(array($new,md5($new),md5($old)));
+
+ if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$old)){
+ $cache->set('fileid/'.$new,$cache->get('fileid/'.$old));
+ $cache->remove('fileid/'.$old);
+ }
}
}
@@ -171,6 +185,8 @@ class OC_FileCache{
//delete everything inside the folder
$query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path LIKE ?');
$query->execute(array($root.$path.'/%'));
+
+ OC_Cache::remove('fileid/'.$root.$path);
}
/**
@@ -245,9 +261,14 @@ class OC_FileCache{
if($root===false){
$root=OC_Filesystem::getRoot();
}
+
+ $fullPath=$root.$path;
+ if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$fullPath)){
+ return $cache->get('fileid/'.$fullPath);
+ }
$query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?');
- $result=$query->execute(array(md5($root.$path)));
+ $result=$query->execute(array(md5($fullPath)));
if(OC_DB::isError($result)){
OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
return -1;
@@ -255,10 +276,15 @@ class OC_FileCache{
$result=$result->fetchRow();
if(is_array($result)){
- return $result['id'];
+ $id=$result['id'];
}else{
- return -1;
+ $id=-1;
+ }
+ if($cache=OC_Cache::getUserCache(true)){
+ $cache->set('fileid/'.$fullPath,$id);
}
+
+ return $id;
}
/**
diff --git a/lib/filesystem.php b/lib/filesystem.php
index ec30ffb8f4c..a5edcf5bab3 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -53,99 +53,99 @@ class OC_Filesystem{
static private $defaultInstance;
- /**
- * classname which used for hooks handling
- * used as signalclass in OC_Hooks::emit()
- */
- const CLASSNAME = 'OC_Filesystem';
-
- /**
- * signalname emited before file renaming
- * @param oldpath
- * @param newpath
- */
- const signal_rename = 'rename';
-
- /**
- * signal emited after file renaming
- * @param oldpath
- * @param newpath
- */
- const signal_post_rename = 'post_rename';
-
- /**
- * signal emited before file/dir creation
- * @param path
- * @param run changing this flag to false in hook handler will cancel event
- */
- const signal_create = 'create';
-
- /**
- * signal emited after file/dir creation
- * @param path
- * @param run changing this flag to false in hook handler will cancel event
- */
- const signal_post_create = 'post_create';
-
- /**
- * signal emits before file/dir copy
- * @param oldpath
- * @param newpath
- * @param run changing this flag to false in hook handler will cancel event
- */
- const signal_copy = 'copy';
-
- /**
- * signal emits after file/dir copy
- * @param oldpath
- * @param newpath
- */
- const signal_post_copy = 'post_copy';
-
- /**
- * signal emits before file/dir save
- * @param path
- * @param run changing this flag to false in hook handler will cancel event
- */
- const signal_write = 'write';
-
- /**
- * signal emits after file/dir save
- * @param path
- */
- const signal_post_write = 'post_write';
-
- /**
- * signal emits when reading file/dir
- * @param path
- */
- const signal_read = 'read';
-
- /**
- * signal emits when removing file/dir
- * @param path
- */
- const signal_delete = 'delete';
-
- /**
- * parameters definitions for signals
- */
- const signal_param_path = 'path';
- const signal_param_oldpath = 'oldpath';
- const signal_param_newpath = 'newpath';
-
- /**
- * run - changing this flag to false in hook handler will cancel event
- */
- const signal_param_run = 'run';
-
- /**
- * get the mountpoint of the storage object for a path
- ( note: because a storage is not always mounted inside the fakeroot, the returned mountpoint is relative to the absolute root of the filesystem and doesn't take the chroot into account
- *
- * @param string path
- * @return string
- */
+ /**
+ * classname which used for hooks handling
+ * used as signalclass in OC_Hooks::emit()
+ */
+ const CLASSNAME = 'OC_Filesystem';
+
+ /**
+ * signalname emited before file renaming
+ * @param oldpath
+ * @param newpath
+ */
+ const signal_rename = 'rename';
+
+ /**
+ * signal emited after file renaming
+ * @param oldpath
+ * @param newpath
+ */
+ const signal_post_rename = 'post_rename';
+
+ /**
+ * signal emited before file/dir creation
+ * @param path
+ * @param run changing this flag to false in hook handler will cancel event
+ */
+ const signal_create = 'create';
+
+ /**
+ * signal emited after file/dir creation
+ * @param path
+ * @param run changing this flag to false in hook handler will cancel event
+ */
+ const signal_post_create = 'post_create';
+
+ /**
+ * signal emits before file/dir copy
+ * @param oldpath
+ * @param newpath
+ * @param run changing this flag to false in hook handler will cancel event
+ */
+ const signal_copy = 'copy';
+
+ /**
+ * signal emits after file/dir copy
+ * @param oldpath
+ * @param newpath
+ */
+ const signal_post_copy = 'post_copy';
+
+ /**
+ * signal emits before file/dir save
+ * @param path
+ * @param run changing this flag to false in hook handler will cancel event
+ */
+ const signal_write = 'write';
+
+ /**
+ * signal emits after file/dir save
+ * @param path
+ */
+ const signal_post_write = 'post_write';
+
+ /**
+ * signal emits when reading file/dir
+ * @param path
+ */
+ const signal_read = 'read';
+
+ /**
+ * signal emits when removing file/dir
+ * @param path
+ */
+ const signal_delete = 'delete';
+
+ /**
+ * parameters definitions for signals
+ */
+ const signal_param_path = 'path';
+ const signal_param_oldpath = 'oldpath';
+ const signal_param_newpath = 'newpath';
+
+ /**
+ * run - changing this flag to false in hook handler will cancel event
+ */
+ const signal_param_run = 'run';
+
+ /**
+ * get the mountpoint of the storage object for a path
+ ( note: because a storage is not always mounted inside the fakeroot, the returned mountpoint is relative to the absolute root of the filesystem and doesn't take the chroot into account
+ *
+ * @param string path
+ * @return string
+ */
static public function getMountPoint($path){
OC_Hook::emit(self::CLASSNAME,'get_mountpoint',array('path'=>$path));
if(!$path){
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index a23d7bbe7fd..9beda01e5a1 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -22,19 +22,19 @@
/**
- * Class to provide access to ownCloud filesystem via a "view", and methods for
- * working with files within that view (e.g. read, write, delete, etc.). Each
- * view is restricted to a set of directories via a virtual root. The default view
- * uses the currently logged in user's data directory as root (parts of
+ * Class to provide access to ownCloud filesystem via a "view", and methods for
+ * working with files within that view (e.g. read, write, delete, etc.). Each
+ * view is restricted to a set of directories via a virtual root. The default view
+ * uses the currently logged in user's data directory as root (parts of
* OC_Filesystem are merely a wrapper for OC_FilesystemView).
- *
+ *
* Apps that need to access files outside of the user data folders (to modify files
* belonging to a user other than the one currently logged in, for example) should
* use this class directly rather than using OC_Filesystem, or making use of PHP's
- * built-in file manipulation functions. This will ensure all hooks and proxies
+ * built-in file manipulation functions. This will ensure all hooks and proxies
* are triggered correctly.
*
- * Filesystem functions are not called directly; they are passed to the correct
+ * Filesystem functions are not called directly; they are passed to the correct
* OC_Filestorage object
*/
@@ -43,11 +43,11 @@ class OC_FilesystemView {
private $internal_path_cache=array();
private $storage_cache=array();
- public function __construct($root){
+ public function __construct($root) {
$this->fakeRoot=$root;
}
- public function getAbsolutePath($path){
+ public function getAbsolutePath($path) {
if(!$path){
$path='/';
}
@@ -63,9 +63,9 @@ class OC_FilesystemView {
* @param string fakeRoot
* @return bool
*/
- public function chroot($fakeRoot){
+ public function chroot($fakeRoot) {
if(!$fakeRoot==''){
- if($fakeRoot[0]!=='/'){
+ if($fakeRoot[0]!=='/') {
$fakeRoot='/'.$fakeRoot;
}
}
@@ -76,7 +76,7 @@ class OC_FilesystemView {
* get the fake root
* @return string
*/
- public function getRoot(){
+ public function getRoot() {
return $this->fakeRoot;
}
@@ -85,7 +85,7 @@ class OC_FilesystemView {
* @param string path
* @return bool
*/
- public function getInternalPath($path){
+ public function getInternalPath($path) {
if (!isset($this->internal_path_cache[$path])) {
$this->internal_path_cache[$path] = OC_Filesystem::getInternalPath($this->getAbsolutePath($path));
}
@@ -97,23 +97,23 @@ class OC_FilesystemView {
* @param string path
* @return string
*/
- public function getRelativePath($path){
- if($this->fakeRoot==''){
+ public function getRelativePath($path) {
+ if($this->fakeRoot=='') {
return $path;
}
- if(strpos($path,$this->fakeRoot)!==0){
+ if(strpos($path, $this->fakeRoot)!==0) {
return null;
}else{
- return substr($path,strlen($this->fakeRoot));
+ return substr($path, strlen($this->fakeRoot));
}
}
-
+
/**
* get the storage object for a path
* @param string path
* @return OC_Filestorage
*/
- public function getStorage($path){
+ public function getStorage($path) {
if (!isset($this->storage_cache[$path])) {
$this->storage_cache[$path] = OC_Filesystem::getStorage($this->getAbsolutePath($path));
}
@@ -127,7 +127,7 @@ class OC_FilesystemView {
* @param string path
* @return string
*/
- public function getMountPoint($path){
+ public function getMountPoint($path) {
return OC_Filesystem::getMountPoint($this->getAbsolutePath($path));
}
@@ -137,55 +137,55 @@ class OC_FilesystemView {
* @param string path
* @return string
*/
- public function getLocalFile($path){
- $parent=substr($path,0,strrpos($path,'/'));
- if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)){
+ public function getLocalFile($path) {
+ $parent=substr($path, 0, strrpos($path,'/'));
+ if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)) {
return $storage->getLocalFile($this->getInternalPath($path));
}
}
/**
- * the following functions operate with arguments and return values identical
- * to those of their PHP built-in equivalents. Mostly they are merely wrappers
+ * the following functions operate with arguments and return values identical
+ * to those of their PHP built-in equivalents. Mostly they are merely wrappers
* for OC_Filestorage via basicOperation().
*/
- public function mkdir($path){
- return $this->basicOperation('mkdir',$path,array('create','write'));
+ public function mkdir($path) {
+ return $this->basicOperation('mkdir', $path, array('create', 'write'));
}
- public function rmdir($path){
- return $this->basicOperation('rmdir',$path,array('delete'));
+ public function rmdir($path) {
+ return $this->basicOperation('rmdir', $path, array('delete'));
}
- public function opendir($path){
- return $this->basicOperation('opendir',$path,array('read'));
+ public function opendir($path) {
+ return $this->basicOperation('opendir', $path, array('read'));
}
- public function readdir($handle){
+ public function readdir($handle) {
$fsLocal= new OC_Filestorage_Local( array( 'datadir' => '/' ) );
return $fsLocal->readdir( $handle );
}
- public function is_dir($path){
+ public function is_dir($path) {
if($path=='/'){
return true;
}
- return $this->basicOperation('is_dir',$path);
+ return $this->basicOperation('is_dir', $path);
}
- public function is_file($path){
+ public function is_file($path) {
if($path=='/'){
return false;
}
- return $this->basicOperation('is_file',$path);
+ return $this->basicOperation('is_file', $path);
}
- public function stat($path){
- return $this->basicOperation('stat',$path);
+ public function stat($path) {
+ return $this->basicOperation('stat', $path);
}
- public function filetype($path){
- return $this->basicOperation('filetype',$path);
+ public function filetype($path) {
+ return $this->basicOperation('filetype', $path);
}
- public function filesize($path){
- return $this->basicOperation('filesize',$path);
+ public function filesize($path) {
+ return $this->basicOperation('filesize', $path);
}
- public function readfile($path){
+ public function readfile($path) {
@ob_end_clean();
- $handle=$this->fopen($path,'rb');
+ $handle=$this->fopen($path, 'rb');
if ($handle) {
$chunkSize = 8192;// 8 MB chunks
while (!feof($handle)) {
@@ -197,137 +197,210 @@ class OC_FilesystemView {
}
return false;
}
- public function is_readable($path){
- return $this->basicOperation('is_readable',$path);
+ public function is_readable($path) {
+ return $this->basicOperation('is_readable', $path);
}
- public function is_writable($path){
- return $this->basicOperation('is_writable',$path);
+ public function is_writable($path) {
+ return $this->basicOperation('is_writable', $path);
}
- public function file_exists($path){
+ public function file_exists($path) {
if($path=='/'){
return true;
}
- return $this->basicOperation('file_exists',$path);
+ return $this->basicOperation('file_exists', $path);
}
- public function filectime($path){
- return $this->basicOperation('filectime',$path);
+ public function filectime($path) {
+ return $this->basicOperation('filectime', $path);
}
- public function filemtime($path){
- return $this->basicOperation('filemtime',$path);
+ public function filemtime($path) {
+ return $this->basicOperation('filemtime', $path);
}
- public function touch($path, $mtime=null){
+ public function touch($path, $mtime=null) {
return $this->basicOperation('touch', $path, array('write'), $mtime);
}
- public function file_get_contents($path){
- return $this->basicOperation('file_get_contents',$path,array('read'));
- }
- public function file_put_contents($path,$data){
- if(is_resource($data)){//not having to deal with streams in file_put_contents makes life easier
- $exists=$this->file_exists($path);
- $run=true;
- if(!$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
+ public function file_get_contents($path) {
+ return $this->basicOperation('file_get_contents', $path, array('read'));
+ }
+ public function file_put_contents($path, $data) {
+ if(is_resource($data)) {//not having to deal with streams in file_put_contents makes life easier
+ $exists = $this->file_exists($path);
+ $run = true;
+ if(!$exists) {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_create,
+ array(
+ OC_Filesystem::signal_param_path => $path,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
}
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
- if(!$run){
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_write,
+ array(
+ OC_Filesystem::signal_param_path => $path,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
+ if(!$run) {
return false;
}
- $target=$this->fopen($path,'w');
- if($target){
- $count=OC_Helper::streamCopy($data,$target);
+ $target=$this->fopen($path, 'w');
+ if($target) {
+ $count=OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
- if(!$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path));
+ if(!$exists) {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_create,
+ array( OC_Filesystem::signal_param_path => $path)
+ );
}
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path));
- return $count>0;
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_write,
+ array( OC_Filesystem::signal_param_path => $path)
+ );
+ return $count > 0;
}else{
return false;
}
}else{
- return $this->basicOperation('file_put_contents',$path,array('create','write'),$data);
+ return $this->basicOperation('file_put_contents', $path, array('create', 'write'), $data);
}
}
- public function unlink($path){
- return $this->basicOperation('unlink',$path,array('delete'));
+ public function unlink($path) {
+ return $this->basicOperation('unlink', $path, array('delete'));
}
public function deleteAll( $directory, $empty = false ) {
return $this->basicOperation( 'deleteAll', $directory, array('delete'), $empty );
}
- public function rename($path1,$path2){
- $absolutePath1=$this->getAbsolutePath($path1);
- $absolutePath2=$this->getAbsolutePath($path2);
- if(OC_FileProxy::runPreProxies('rename',$absolutePath1,$absolutePath2) and OC_Filesystem::isValidPath($path2)){
- $path1=$this->getRelativePath($absolutePath1);
- $path2=$this->getRelativePath($absolutePath2);
- if($path1==null or $path2==null){
+ public function rename($path1, $path2) {
+ $absolutePath1 = $this->getAbsolutePath($path1);
+ $absolutePath2 = $this->getAbsolutePath($path2);
+ if(OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
+ $path1 = $this->getRelativePath($absolutePath1);
+ $path2 = $this->getRelativePath($absolutePath2);
+ if($path1 == null or $path2 == null) {
return false;
}
$run=true;
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run));
- if($run){
- $mp1=$this->getMountPoint($path1);
- $mp2=$this->getMountPoint($path2);
- if($mp1==$mp2){
- if($storage=$this->getStorage($path1)){
- $result=$storage->rename($this->getInternalPath($path1),$this->getInternalPath($path2));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename,
+ array(
+ OC_Filesystem::signal_param_oldpath => $path1,
+ OC_Filesystem::signal_param_newpath => $path2,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
+ if($run) {
+ $mp1 = $this->getMountPoint($path1);
+ $mp2 = $this->getMountPoint($path2);
+ if($mp1 == $mp2) {
+ if($storage = $this->getStorage($path1)) {
+ $result = $storage->rename($this->getInternalPath($path1), $this->getInternalPath($path2));
}
- }else{
- $source=$this->fopen($path1,'r');
- $target=$this->fopen($path2,'w');
- $count=OC_Helper::streamCopy($source,$target);
- $storage1=$this->getStorage($path1);
+ } else {
+ $source = $this->fopen($path1, 'r');
+ $target = $this->fopen($path2, 'w');
+ $count = OC_Helper::streamCopy($source, $target);
+ $storage1 = $this->getStorage($path1);
$storage1->unlink($this->getInternalPath($path1));
- $result=$count>0;
+ $result = $count>0;
}
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, array( OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath=>$path2));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_rename,
+ array(
+ OC_Filesystem::signal_param_oldpath => $path1,
+ OC_Filesystem::signal_param_newpath => $path2
+ )
+ );
return $result;
}
}
}
- public function copy($path1,$path2){
- $absolutePath1=$this->getAbsolutePath($path1);
- $absolutePath2=$this->getAbsolutePath($path2);
- if(OC_FileProxy::runPreProxies('copy',$absolutePath1,$absolutePath2) and OC_Filesystem::isValidPath($path2)){
- $path1=$this->getRelativePath($absolutePath1);
- $path2=$this->getRelativePath($absolutePath2);
- if($path1==null or $path2==null){
+ public function copy($path1, $path2) {
+ $absolutePath1 = $this->getAbsolutePath($path1);
+ $absolutePath2 = $this->getAbsolutePath($path2);
+ if(OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
+ $path1 = $this->getRelativePath($absolutePath1);
+ $path2 = $this->getRelativePath($absolutePath2);
+ if($path1 == null or $path2 == null) {
return false;
}
$run=true;
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_copy,
+ array(
+ OC_Filesystem::signal_param_oldpath => $path1,
+ OC_Filesystem::signal_param_newpath=>$path2,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
$exists=$this->file_exists($path2);
- if($run and !$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
+ if($run and !$exists) {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_create,
+ array(
+ OC_Filesystem::signal_param_path => $path2,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
}
- if($run){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path2, OC_Filesystem::signal_param_run => &$run));
+ if($run) {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_write,
+ array(
+ OC_Filesystem::signal_param_path => $path2,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
}
- if($run){
+ if($run) {
$mp1=$this->getMountPoint($path1);
$mp2=$this->getMountPoint($path2);
- if($mp1==$mp2){
- if($storage=$this->getStorage($path1)){
- $result=$storage->copy($this->getInternalPath($path1),$this->getInternalPath($path2));
+ if($mp1 == $mp2){
+ if($storage = $this->getStorage($path1)) {
+ $result=$storage->copy($this->getInternalPath($path1), $this->getInternalPath($path2));
}
- }else{
- $source=$this->fopen($path1,'r');
- $target=$this->fopen($path2,'w');
- $result=OC_Helper::streamCopy($source,$target);
+ } else {
+ $source = $this->fopen($path1, 'r');
+ $target = $this->fopen($path2, 'w');
+ $result = OC_Helper::streamCopy($source, $target);
}
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2));
- if(!$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path2));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_copy,
+ array(
+ OC_Filesystem::signal_param_oldpath => $path1,
+ OC_Filesystem::signal_param_newpath=>$path2
+ )
+ );
+ if(!$exists) {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_create,
+ array(OC_Filesystem::signal_param_path => $path2)
+ );
}
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path2));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ OC_Filesystem::signal_post_write,
+ array( OC_Filesystem::signal_param_path => $path2)
+ );
return $result;
}
}
}
- public function fopen($path,$mode){
+ public function fopen($path, $mode) {
$hooks=array();
- switch($mode){
+ switch($mode) {
case 'r':
case 'rb':
$hooks[]='read';
@@ -355,49 +428,49 @@ class OC_FilesystemView {
OC_Log::write('core','invalid mode ('.$mode.') for '.$path,OC_Log::ERROR);
}
- return $this->basicOperation('fopen',$path,$hooks,$mode);
+ return $this->basicOperation('fopen', $path, $hooks, $mode);
}
- public function toTmpFile($path){
- if(OC_Filesystem::isValidPath($path)){
- $source=$this->fopen($path,'r');
- if($source){
+ public function toTmpFile($path) {
+ if(OC_Filesystem::isValidPath($path)) {
+ $source = $this->fopen($path, 'r');
+ if($source) {
$extension='';
- $extOffset=strpos($path,'.');
+ $extOffset=strpos($path, '.');
if($extOffset !== false) {
- $extension=substr($path,strrpos($path,'.'));
+ $extension=substr($path, strrpos($path,'.'));
}
- $tmpFile=OC_Helper::tmpFile($extension);
- file_put_contents($tmpFile,$source);
+ $tmpFile = OC_Helper::tmpFile($extension);
+ file_put_contents($tmpFile, $source);
return $tmpFile;
}
}
}
- public function fromTmpFile($tmpFile,$path){
- if(OC_Filesystem::isValidPath($path)){
- if(!$tmpFile){
+ public function fromTmpFile($tmpFile, $path) {
+ if(OC_Filesystem::isValidPath($path)) {
+ if(!$tmpFile) {
debug_print_backtrace();
}
- $source=fopen($tmpFile,'r');
- if($source){
- $this->file_put_contents($path,$source);
+ $source=fopen($tmpFile, 'r');
+ if($source) {
+ $this->file_put_contents($path, $source);
unlink($tmpFile);
return true;
- }else{
+ } else {
}
- }else{
+ } else {
return false;
}
}
- public function getMimeType($path){
- return $this->basicOperation('getMimeType',$path);
+ public function getMimeType($path) {
+ return $this->basicOperation('getMimeType', $path);
}
- public function hash($type,$path){
- return $this->basicOperation('hash',$path,array('read'),$type);
+ public function hash($type, $path) {
+ return $this->basicOperation('hash', $path, array('read'), $type);
}
- public function free_space($path='/'){
- return $this->basicOperation('free_space',$path);
+ public function free_space($path='/') {
+ return $this->basicOperation('free_space', $path);
}
/**
@@ -407,41 +480,56 @@ class OC_FilesystemView {
* @param array (optional) hooks
* @param mixed (optional) $extraParam
* @return mixed
- *
- * This method takes requests for basic filesystem functions (e.g. reading & writing
- * files), processes hooks and proxies, sanitises paths, and finally passes them on to
+ *
+ * This method takes requests for basic filesystem functions (e.g. reading & writing
+ * files), processes hooks and proxies, sanitises paths, and finally passes them on to
* OC_Filestorage for delegation to a storage backend for execution
*/
- private function basicOperation($operation,$path,$hooks=array(),$extraParam=null){
- $absolutePath=$this->getAbsolutePath($path);
- if(OC_FileProxy::runPreProxies($operation,$absolutePath, $extraParam) and OC_Filesystem::isValidPath($path)){
- $path=$this->getRelativePath($absolutePath);
- if($path==null){
+ private function basicOperation($operation, $path, $hooks=array(), $extraParam=null) {
+ $absolutePath = $this->getAbsolutePath($path);
+ if(OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and OC_Filesystem::isValidPath($path)) {
+ $path = $this->getRelativePath($absolutePath);
+ if($path == null) {
return false;
}
- $internalPath=$this->getInternalPath($path);
- $run=true;
- if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){
- foreach($hooks as $hook){
- if($hook!='read'){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
- }else{
- OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path));
+ $internalPath = $this->getInternalPath($path);
+ $run = true;
+ if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) {
+ foreach($hooks as $hook) {
+ if($hook!='read') {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ $hook,
+ array(
+ OC_Filesystem::signal_param_path => $path,
+ OC_Filesystem::signal_param_run => &$run
+ )
+ );
+ } else {
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ $hook,
+ array( OC_Filesystem::signal_param_path => $path)
+ );
}
}
}
- if($run and $storage=$this->getStorage($path)){
- if(!is_null($extraParam)){
- $result=$storage->$operation($internalPath,$extraParam);
- }else{
- $result=$storage->$operation($internalPath);
+ if($run and $storage = $this->getStorage($path)) {
+ if(!is_null($extraParam)) {
+ $result = $storage->$operation($internalPath, $extraParam);
+ } else {
+ $result = $storage->$operation($internalPath);
}
- $result=OC_FileProxy::runPostProxies($operation,$this->getAbsolutePath($path),$result);
- if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){
- if($operation!='fopen'){//no post hooks for fopen, the file stream is still open
- foreach($hooks as $hook){
+ $result = OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result);
+ if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) {
+ if($operation!='fopen') {//no post hooks for fopen, the file stream is still open
+ foreach($hooks as $hook) {
if($hook!='read'){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path));
+ OC_Hook::emit(
+ OC_Filesystem::CLASSNAME,
+ 'post_'.$hook,
+ array( OC_Filesystem::signal_param_path => $path)
+ );
}
}
}
@@ -457,7 +545,7 @@ class OC_FilesystemView {
* @param int $time
* @return bool
*/
- public function hasUpdated($path,$time){
- return $this->basicOperation('hasUpdated',$path,array(),$time);
+ public function hasUpdated($path, $time) {
+ return $this->basicOperation('hasUpdated', $path, array(), $time);
}
}
diff --git a/lib/helper.php b/lib/helper.php
index c4f7e8b2e19..f328c14ac77 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -175,10 +175,8 @@ class OC_Helper {
*/
public static function mimetypeIcon( $mimetype ){
$alias=array('application/xml'=>'code/xml');
-// echo $mimetype;
if(isset($alias[$mimetype])){
$mimetype=$alias[$mimetype];
-// echo $mimetype;
}
// Replace slash with a minus
$mimetype = str_replace( "/", "-", $mimetype );
@@ -345,18 +343,24 @@ class OC_Helper {
*/
static function getMimeType($path){
$isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://');
- $mimeType='application/octet-stream';
- if ($mimeType=='application/octet-stream') {
- self::$mimetypes = include('mimetypes.fixlist.php');
- $extension=strtolower(strrchr(basename($path), "."));
- $extension=substr($extension,1);//remove leading .
- $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
- }
if (@is_dir($path)) {
// directories are easy
return "httpd/unix-directory";
}
+
+ if(strpos($path,'.')){
+ //try to guess the type by the file extension
+ if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){
+ self::$mimetypes=include('mimetypes.list.php');
+ }
+ $extension=strtolower(strrchr(basename($path), "."));
+ $extension=substr($extension,1);//remove leading .
+ $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
+ }else{
+ $mimeType='application/octet-stream';
+ }
+
if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)){
$info = @strtolower(finfo_file($finfo,$path));
if($info){
@@ -385,15 +389,6 @@ class OC_Helper {
}
}
- if ($mimeType=='application/octet-stream') {
- // Fallback solution: (try to guess the type by the file extension
- if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){
- self::$mimetypes=include('mimetypes.list.php');
- }
- $extension=strtolower(strrchr(basename($path), "."));
- $extension=substr($extension,1);//remove leading .
- $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
- }
return $mimeType;
}
diff --git a/lib/image.php b/lib/image.php
index c438b3d67f6..90c64320a7c 100644
--- a/lib/image.php
+++ b/lib/image.php
@@ -23,12 +23,12 @@
//From user comments at http://dk2.php.net/manual/en/function.exif-imagetype.php
if ( ! function_exists( 'exif_imagetype' ) ) {
- function exif_imagetype ( $filename ) {
- if ( ( $info = getimagesize( $filename ) ) !== false ) {
- return $info[2];
- }
- return false;
- }
+ function exif_imagetype ( $filename ) {
+ if ( ( $info = getimagesize( $filename ) ) !== false ) {
+ return $info[2];
+ }
+ return false;
+ }
}
function ellipsis($str, $maxlen) {
@@ -66,7 +66,6 @@ class OC_Image {
public function __construct($imageref = null) {
//OC_Log::write('core',__METHOD__.'(): start', OC_Log::DEBUG);
if(!extension_loaded('gd') || !function_exists('gd_info')) {
- //if(!function_exists('imagecreatefromjpeg')) {
OC_Log::write('core',__METHOD__.'(): GD module not installed', OC_Log::ERROR);
return false;
}
diff --git a/lib/installer.php b/lib/installer.php
index 00feb6d4709..a8b56cb34f2 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -126,19 +126,19 @@ class OC_Installer{
return false;
}
$info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml',true);
- // check the code for not allowed calls
- if(!OC_Installer::checkCode($info['id'],$extractDir)){
+ // check the code for not allowed calls
+ if(!OC_Installer::checkCode($info['id'],$extractDir)){
OC_Log::write('core','App can\'t be installed because of not allowed code in the App',OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
- return false;
+ return false;
}
- // check if the app is compatible with this version of ownCloud
+ // check if the app is compatible with this version of ownCloud
$version=OC_Util::getVersion();
- if(!isset($info['require']) or ($version[0]>$info['require'])){
+ if(!isset($info['require']) or ($version[0]>$info['require'])){
OC_Log::write('core','App can\'t be installed because it is not compatible with this version of ownCloud',OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
- return false;
+ return false;
}
//check if an app with the same id is already installed
@@ -339,12 +339,12 @@ class OC_Installer{
}
- /**
- * check the code of an app with some static code checks
- * @param string $folder the folder of the app to check
- * @returns true for app is o.k. and false for app is not o.k.
- */
- public static function checkCode($appname,$folder){
+ /**
+ * check the code of an app with some static code checks
+ * @param string $folder the folder of the app to check
+ * @returns true for app is o.k. and false for app is not o.k.
+ */
+ public static function checkCode($appname,$folder){
$blacklist=array(
'exec(',
@@ -377,9 +377,7 @@ class OC_Installer{
return true;
}else{
- return true;
+ return true;
}
- }
-
-
+ }
}
diff --git a/lib/json.php b/lib/json.php
index c49b831c12b..b46878375d5 100644
--- a/lib/json.php
+++ b/lib/json.php
@@ -94,12 +94,12 @@ class OC_JSON{
* Encode and print $data in json format
*/
public static function encodedPrint($data,$setContentType=true){
- // Disable mimesniffing, don't move this to setContentTypeHeader!
- header( 'X-Content-Type-Options: nosniff' );
- if($setContentType){
- self::setContentTypeHeader();
- }
- array_walk_recursive($data, array('OC_JSON', 'to_string'));
- echo json_encode($data);
+ // Disable mimesniffing, don't move this to setContentTypeHeader!
+ header( 'X-Content-Type-Options: nosniff' );
+ if($setContentType){
+ self::setContentTypeHeader();
+ }
+ array_walk_recursive($data, array('OC_JSON', 'to_string'));
+ echo json_encode($data);
}
}
diff --git a/lib/mimetypes.fixlist.php b/lib/mimetypes.fixlist.php
deleted file mode 100644
index 13e3f16b369..00000000000
--- a/lib/mimetypes.fixlist.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-return array(
- 'ics'=>'text/calendar',
- 'ical'=>'text/calendar',
- 'js'=>'application/javascript',
- 'odt'=>'application/vnd.oasis.opendocument.text',
- 'ods'=>'application/vnd.oasis.opendocument.spreadsheet',
- 'odg'=>'application/vnd.oasis.opendocument.graphics',
- 'odp'=>'application/vnd.oasis.opendocument.presentation',
- 'pl'=>'text/x-script.perl',
- 'py'=>'text/x-script.phyton',
- 'vcf' => 'text/vcard',
- 'vcard' => 'text/vcard',
- 'doc'=>'application/msword',
- 'docx'=>'application/msword',
- 'xls'=>'application/msexcel',
- 'xlsx'=>'application/msexcel',
- 'ppt'=>'application/mspowerpoint',
- 'pptx'=>'application/mspowerpoint',
- 'sgf' => 'application/sgf',
- 'cdr' => 'application/coreldraw'
-);
diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php
index ccf47999b1c..f7207493f7f 100644
--- a/lib/mimetypes.list.php
+++ b/lib/mimetypes.list.php
@@ -78,5 +78,16 @@ return array(
'mpeg'=>'video/mpeg',
'mov'=>'video/quicktime',
'webm'=>'video/webm',
- 'wmv'=>'video/x-ms-asf'
+ 'wmv'=>'video/x-ms-asf',
+ 'py'=>'text/x-script.phyton',
+ 'vcf' => 'text/vcard',
+ 'vcard' => 'text/vcard',
+ 'doc'=>'application/msword',
+ 'docx'=>'application/msword',
+ 'xls'=>'application/msexcel',
+ 'xlsx'=>'application/msexcel',
+ 'ppt'=>'application/mspowerpoint',
+ 'pptx'=>'application/mspowerpoint',
+ 'sgf' => 'application/sgf',
+ 'cdr' => 'application/coreldraw',
);
diff --git a/lib/minimizer.php b/lib/minimizer.php
index 3bf5ff9980b..3dc89e331a6 100644
--- a/lib/minimizer.php
+++ b/lib/minimizer.php
@@ -46,3 +46,13 @@ abstract class OC_Minimizer {
echo $out;
}
}
+
+if (!function_exists('gzdecode')) {
+ function gzdecode($data,$maxlength=null,&$filename='',&$error='')
+ {
+ if (strcmp(substr($data,0,9),"\x1f\x8b\x8\0\0\0\0\0\0")) {
+ return null; // Not the GZIP format we expect (See RFC 1952)
+ }
+ return gzinflate(substr($data,10,-8));
+ }
+}
diff --git a/lib/ocs.php b/lib/ocs.php
index 27007076661..18f01518bdb 100644
--- a/lib/ocs.php
+++ b/lib/ocs.php
@@ -4,7 +4,9 @@
* ownCloud
*
* @author Frank Karlitschek
+* @author Michael Gapczynski
* @copyright 2012 Frank Karlitschek frank@owncloud.org
+* @copyright 2012 Michael Gapczynski mtgap@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
@@ -27,431 +29,476 @@
*/
class OC_OCS {
- /**
- * reads input date from get/post/cookies and converts the date to a special data-type
- *
- * @param variable $key
- * @param variable-type $type
- * @param priority $getpriority
- * @param default $default
- * @return data
- */
- public static function readData($key,$type='raw',$getpriority=false,$default='') {
- if($getpriority) {
- if(isset($_GET[$key])) {
- $data=$_GET[$key];
- } elseif(isset($_POST[$key])) {
- $data=$_POST[$key];
- } else {
- if($default=='') {
- if(($type=='int') or ($type=='float')) $data=0; else $data='';
- } else {
- $data=$default;
- }
- }
- } else {
- if(isset($_POST[$key])) {
- $data=$_POST[$key];
- } elseif(isset($_GET[$key])) {
- $data=$_GET[$key];
- } elseif(isset($_COOKIE[$key])) {
- $data=$_COOKIE[$key];
- } else {
- if($default=='') {
- if(($type=='int') or ($type=='float')) $data=0; else $data='';
- } else {
- $data=$default;
- }
- }
- }
-
- if($type=='raw') return($data);
- elseif($type=='text') return(addslashes(strip_tags($data)));
- elseif($type=='int') { $data = (int) $data; return($data); }
- elseif($type=='float') { $data = (float) $data; return($data); }
- elseif($type=='array') { $data = $data; return($data); }
- }
-
-
- /**
- main function to handle the REST request
- **/
- public static function handle() {
-
- // overwrite the 404 error page returncode
- header("HTTP/1.0 200 OK");
-
- $router = new OC_Router();
- $router->useCollection('ocs');
- // CONFIG
- $router->create('config', '/config.{format}')
- ->defaults(array('format'=>''))
- ->action('OC_OCS', 'apiConfig')
- ->requirements(array('format'=>'xml|json'));
-
- // PERSON
- $router->create('person_check', '/person/check.{format}')
- ->post()
- ->defaults(array('format'=>''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $login=OC_OCS::readdata('login','text');
- $passwd=OC_OCS::readdata('password','text');
- OC_OCS::personcheck($format,$login,$passwd);
- })
- ->requirements(array('format'=>'xml|json'));
-
- // ACTIVITY
- // activityget - GET ACTIVITY page,pagesize als urlparameter
- $router->create('activity_get', '/activity.{format}')
- ->defaults(array('format'=>''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $page=OC_OCS::readdata('page','int');
- $pagesize=OC_OCS::readdata('pagesize','int');
- if($pagesize<1 or $pagesize>100) $pagesize=10;
- OC_OCS::activityget($format,$page,$pagesize);
- })
- ->requirements(array('format'=>'xml|json'));
- // activityput - POST ACTIVITY
- $router->create('activity_put', '/activity.{format}')
- ->post()
- ->defaults(array('format'=>''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $message=OC_OCS::readdata('message','text');
- OC_OCS::activityput($format,$message);
- })
- ->requirements(array('format'=>'xml|json'));
-
- // PRIVATEDATA
- // get - GET DATA
- $router->create('privatedata_get',
- '/privatedata/getattribute/{app}/{key}.{format}')
- ->defaults(array('app' => '', 'key' => '', 'format' => ''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $app = addslashes(strip_tags($parameters['app']));
- $key = addslashes(strip_tags($parameters['key']));
- OC_OCS::privateDataGet($format, $app, $key);
- })
- ->requirements(array('format'=>'xml|json'));
- // set - POST DATA
- $router->create('privatedata_set',
- '/privatedata/setattribute/{app}/{key}.{format}')
- ->post()
- ->defaults(array('format'=>''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $app = addslashes(strip_tags($parameters['app']));
- $key = addslashes(strip_tags($parameters['key']));
- $value=OC_OCS::readdata('value','text');
- OC_OCS::privateDataSet($format, $app, $key, $value);
- })
- ->requirements(array('format'=>'xml|json'));
- // delete - POST DATA
- $router->create('privatedata_delete',
- '/privatedata/deleteattribute/{app}/{key}.{format}')
- ->post()
- ->defaults(array('format'=>''))
- ->action(function ($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $app = addslashes(strip_tags($parameters['app']));
- $key = addslashes(strip_tags($parameters['key']));
- OC_OCS::privateDataDelete($format, $app, $key);
- })
- ->requirements(array('format'=>'xml|json'));
-
- try {
- $router->match($_SERVER['PATH_INFO']);
- } catch (ResourceNotFoundException $e) {
- $format=OC_OCS::readdata('format','text');
- $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
- $txt.=OC_OCS::getdebugoutput();
- echo(OC_OCS::generatexml($format,'failed',999,$txt));
- }
- exit();
- }
-
- /**
- * generated some debug information to make it easier to find faild API calls
- * @return debug data string
- */
- private static function getDebugOutput() {
- $txt='';
- $txt.="debug output:\n";
- if(isset($_SERVER['REQUEST_METHOD'])) $txt.='http request method: '.$_SERVER['REQUEST_METHOD']."\n";
- if(isset($_SERVER['REQUEST_URI'])) $txt.='http request uri: '.$_SERVER['REQUEST_URI']."\n";
- if(isset($_GET)) foreach($_GET as $key=>$value) $txt.='get parameter: '.$key.'->'.$value."\n";
- if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n";
- return($txt);
- }
-
- /**
- * checks if the user is authenticated
- * checks the IP whitlist, apikeys and login/password combination
- * if $forceuser is true and the authentication failed it returns an 401 http response.
- * if $forceuser is false and authentification fails it returns an empty username string
- * @param bool $forceuser
- * @return username string
- */
- private static function checkPassword($forceuser=true) {
- //valid user account ?
- if(isset($_SERVER['PHP_AUTH_USER'])) $authuser=$_SERVER['PHP_AUTH_USER']; else $authuser='';
- if(isset($_SERVER['PHP_AUTH_PW'])) $authpw=$_SERVER['PHP_AUTH_PW']; else $authpw='';
-
- if(empty($authuser)) {
- if($forceuser){
- header('WWW-Authenticate: Basic realm="your valid user account or api key"');
- header('HTTP/1.0 401 Unauthorized');
- exit;
- }else{
- $identifieduser='';
- }
- }else{
- if(!OC_User::login($authuser,$authpw)){
- if($forceuser){
- header('WWW-Authenticate: Basic realm="your valid user account or api key"');
- header('HTTP/1.0 401 Unauthorized');
- exit;
- }else{
- $identifieduser='';
- }
- }else{
- $identifieduser=$authuser;
- }
- }
-
- return($identifieduser);
- }
-
-
- /**
- * generates the xml or json response for the API call from an multidimenional data array.
- * @param string $format
- * @param string $status
- * @param string $statuscode
- * @param string $message
- * @param array $data
- * @param string $tag
- * @param string $tagattribute
- * @param int $dimension
- * @param int $itemscount
- * @param int $itemsperpage
- * @return string xml/json
- */
- private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
- if($format=='json') {
-
- $json=array();
- $json['status']=$status;
- $json['statuscode']=$statuscode;
- $json['message']=$message;
- $json['totalitems']=$itemscount;
- $json['itemsperpage']=$itemsperpage;
- $json['data']=$data;
- return(json_encode($json));
-
-
- }else{
- $txt='';
- $writer = xmlwriter_open_memory();
- xmlwriter_set_indent( $writer, 2 );
- xmlwriter_start_document($writer );
- xmlwriter_start_element($writer,'ocs');
- xmlwriter_start_element($writer,'meta');
- xmlwriter_write_element($writer,'status',$status);
- xmlwriter_write_element($writer,'statuscode',$statuscode);
- xmlwriter_write_element($writer,'message',$message);
- if($itemscount<>'') xmlwriter_write_element($writer,'totalitems',$itemscount);
- if(!empty($itemsperpage)) xmlwriter_write_element($writer,'itemsperpage',$itemsperpage);
- xmlwriter_end_element($writer);
- if($dimension=='0') {
- // 0 dimensions
- xmlwriter_write_element($writer,'data',$data);
-
- }elseif($dimension=='1') {
- xmlwriter_start_element($writer,'data');
- foreach($data as $key=>$entry) {
- xmlwriter_write_element($writer,$key,$entry);
- }
- xmlwriter_end_element($writer);
-
- }elseif($dimension=='2') {
- xmlwriter_start_element($writer,'data');
- foreach($data as $entry) {
- xmlwriter_start_element($writer,$tag);
- if(!empty($tagattribute)) {
- xmlwriter_write_attribute($writer,'details',$tagattribute);
- }
- foreach($entry as $key=>$value) {
- if(is_array($value)){
- foreach($value as $k=>$v) {
- xmlwriter_write_element($writer,$k,$v);
- }
- } else {
- xmlwriter_write_element($writer,$key,$value);
- }
- }
- xmlwriter_end_element($writer);
- }
- xmlwriter_end_element($writer);
-
- }elseif($dimension=='3') {
- xmlwriter_start_element($writer,'data');
- foreach($data as $entrykey=>$entry) {
- xmlwriter_start_element($writer,$tag);
- if(!empty($tagattribute)) {
- xmlwriter_write_attribute($writer,'details',$tagattribute);
- }
- foreach($entry as $key=>$value) {
- if(is_array($value)){
- xmlwriter_start_element($writer,$entrykey);
- foreach($value as $k=>$v) {
- xmlwriter_write_element($writer,$k,$v);
- }
- xmlwriter_end_element($writer);
- } else {
- xmlwriter_write_element($writer,$key,$value);
- }
- }
- xmlwriter_end_element($writer);
- }
- xmlwriter_end_element($writer);
- }elseif($dimension=='dynamic') {
- xmlwriter_start_element($writer,'data');
- OC_OCS::toxml($writer,$data,'comment');
- xmlwriter_end_element($writer);
- }
-
- xmlwriter_end_element($writer);
-
- xmlwriter_end_document( $writer );
- $txt.=xmlwriter_output_memory( $writer );
- unset($writer);
- return($txt);
- }
- }
-
- public static function toXml($writer,$data,$node) {
- foreach($data as $key => $value) {
- if (is_numeric($key)) {
- $key = $node;
- }
- if (is_array($value)){
- xmlwriter_start_element($writer,$key);
- OC_OCS::toxml($writer,$value,$node);
- xmlwriter_end_element($writer);
- }else{
- xmlwriter_write_element($writer,$key,$value);
- }
-
- }
- }
-
-
-
-
- /**
- * return the config data of this server
- * @param string $format
- * @return string xml/json
- */
- public static function apiConfig($parameters) {
- $format = $parameters['format'] ? $parameters['format'] : OC_OCS::readdata('format','text');
- $xml['version']='1.5';
- $xml['website']='ownCloud';
- $xml['host']=OCP\Util::getServerHost();
- $xml['contact']='';
- $xml['ssl']='false';
- echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'config','',1));
- }
-
-
- /**
- * check if the provided login/apikey/password is valid
- * @param string $format
- * @param string $login
- * @param string $passwd
- * @return string xml/json
- */
- private static function personCheck($format,$login,$passwd) {
- if($login<>''){
- if(OC_User::login($login,$passwd)){
- $xml['person']['personid']=$login;
- echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'person','check',2));
- }else{
- echo(OC_OCS::generatexml($format,'failed',102,'login not valid'));
- }
- }else{
- echo(OC_OCS::generatexml($format,'failed',101,'please specify all mandatory fields'));
- }
- }
-
-
-
- // ACTIVITY API #############################################
-
- /**
- * get my activities
- * @param string $format
- * @param string $page
- * @param string $pagesize
- * @return string xml/json
- */
- private static function activityGet($format,$page,$pagesize) {
- $user=OC_OCS::checkpassword();
-
- //TODO
-
- $txt=OC_OCS::generatexml($format,'ok',100,'',$xml,'activity','full',2,$totalcount,$pagesize);
- echo($txt);
- }
-
- /**
- * submit a activity
- * @param string $format
- * @param string $message
- * @return string xml/json
- */
- private static function activityPut($format,$message) {
- // not implemented in ownCloud
- OC_OCS::checkpassword();
- echo(OC_OCS::generatexml($format,'ok',100,''));
- }
-
- // PRIVATEDATA API #############################################
-
- /**
- * get private data and create the xml for ocs
- * @param string $format
- * @param string $app
- * @param string $key
- * @return string xml/json
- */
- private static function privateDataGet($format,$app="",$key="") {
- $user=OC_OCS::checkpassword();
- $result=OC_OCS::getData($user,$app,$key);
- $xml=array();
- foreach($result as $i=>$log) {
- $xml[$i]['key']=$log['key'];
- $xml[$i]['app']=$log['app'];
- $xml[$i]['value']=$log['value'];
- }
-
-
- $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'privatedata', 'full', 2, count($xml), 0);//TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it
- echo($txt);
- }
-
- /**
- * set private data referenced by $key to $value and generate the xml for ocs
- * @param string $format
- * @param string $app
- * @param string $key
- * @param string $value
- * @return string xml/json
- */
+ /**
+ * reads input date from get/post/cookies and converts the date to a special data-type
+ *
+ * @param string HTTP method to read the key from
+ * @param string Parameter to read
+ * @param string Variable type to format data
+ * @param mixed Default value to return if the key is not found
+ * @return mixed Data or if the key is not found and no default is set it will exit with a 400 Bad request
+ */
+ public static function readData($method, $key, $type = 'raw', $default = null) {
+ if ($method == 'get') {
+ if (isset($_GET[$key])) {
+ $data = $_GET[$key];
+ } else if (isset($default)) {
+ return $default;
+ } else {
+ $data = false;
+ }
+ } else if ($method == 'post') {
+ if (isset($_POST[$key])) {
+ $data = $_POST[$key];
+ } else if (isset($default)) {
+ return $default;
+ } else {
+ $data = false;
+ }
+ }
+ if ($data === false) {
+ echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key);
+ exit();
+ } else {
+ // NOTE: Is the raw type necessary? It might be a little risky without sanitization
+ if ($type == 'raw') return $data;
+ elseif ($type == 'text') return OC_Util::sanitizeHTML($data);
+ elseif ($type == 'int') return (int) $data;
+ elseif ($type == 'float') return (float) $data;
+ elseif ($type == 'array') return OC_Util::sanitizeHTML($data);
+ else return OC_Util::sanitizeHTML($data);
+ }
+ }
+
+ /**
+ main function to handle the REST request
+ **/
+ public static function handle() {
+ // overwrite the 404 error page returncode
+ header("HTTP/1.0 200 OK");
+
+
+ if($_SERVER['REQUEST_METHOD'] == 'GET') {
+ $method='get';
+ }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
+ $method='put';
+ parse_str(file_get_contents("php://input"),$put_vars);
+ }elseif($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $method='post';
+ }else{
+ echo('internal server error: method not supported');
+ exit();
+ }
+
+ // preprocess url
+ $url = strtolower($_SERVER['REQUEST_URI']);
+ $format = self::readData($method, 'format', 'text', '');
+
+ $router = new OC_Router();
+ $router->useCollection('ocs');
+ // CONFIG
+ $router->create('config', '/config.{format}')
+ ->defaults(array('format' => $format))
+ ->action('OC_OCS', 'apiConfig')
+ ->requirements(array('format'=>'xml|json'));
+
+ // PERSON
+ $router->create('person_check', '/person/check.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $login = OC_OCS::readData('post', 'login', 'text');
+ $passwd = OC_OCS::readData('post', 'password', 'text');
+ OC_OCS::personCheck($format,$login,$passwd);
+ })
+ ->requirements(array('format'=>'xml|json'));
+
+ // ACTIVITY
+ // activityget - GET ACTIVITY page,pagesize als urlparameter
+ $router->create('activity_get', '/activity.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $page = OC_OCS::readData('get', 'page', 'int', 0);
+ $pagesize = OC_OCS::readData('get', 'pagesize', 'int', 10);
+ if($pagesize<1 or $pagesize>100) $pagesize=10;
+ OC_OCS::activityGet($format, $page, $pagesize);
+ })
+ ->requirements(array('format'=>'xml|json'));
+ // activityput - POST ACTIVITY
+ $router->create('activity_put', '/activity.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $message = OC_OCS::readData('post', 'message', 'text');
+ OC_OCS::activityPut($format,$message);
+ })
+ ->requirements(array('format'=>'xml|json'));
+
+ // PRIVATEDATA
+ // get - GET DATA
+ $router->create('privatedata_get',
+ '/privatedata/getattribute/{app}/{key}.{format}')
+ ->defaults(array('app' => '', 'key' => '', 'format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ OC_OCS::privateDataGet($format, $app, $key);
+ })
+ ->requirements(array('format'=>'xml|json'));
+ // set - POST DATA
+ $router->create('privatedata_set',
+ '/privatedata/setattribute/{app}/{key}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ $value=OC_OCS::readData('post', 'value', 'text');
+ OC_OCS::privateDataSet($format, $app, $key, $value);
+ })
+ ->requirements(array('format'=>'xml|json'));
+ // delete - POST DATA
+ $router->create('privatedata_delete',
+ '/privatedata/deleteattribute/{app}/{key}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ OC_OCS::privateDataDelete($format, $app, $key);
+ })
+ ->requirements(array('format'=>'xml|json'));
+
+ // CLOUD
+ // quotaget
+ $router->create('quota_get',
+ '/cloud/user/{user}.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ OC_OCS::quotaGet($format, $user);
+ })
+ ->requirements(array('format'=>'xml|json'));
+ // quotaset
+ $router->create('quota_set',
+ '/cloud/user/{user}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ $quota = self::readData('post', 'quota', 'int');
+ OC_OCS::quotaSet($format, $user, $quota);
+ })
+ ->requirements(array('format'=>'xml|json'));
+
+
+// add more calls here
+// please document all the call in the draft spec
+// http://www.freedesktop.org/wiki/Specifications/open-collaboration-services-1.7#CLOUD
+
+// TODO:
+// users
+// groups
+// bookmarks
+// sharing
+// versioning
+// news (rss)
+ try {
+ $router->match($_SERVER['PATH_INFO']);
+ } catch (ResourceNotFoundException $e) {
+ $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
+ $txt.=OC_OCS::getdebugoutput();
+ echo(OC_OCS::generatexml($format,'failed',999,$txt));
+ }
+ exit();
+ }
+
+ /**
+ * generated some debug information to make it easier to find faild API calls
+ * @return debug data string
+ */
+ private static function getDebugOutput() {
+ $txt='';
+ $txt.="debug output:\n";
+ if(isset($_SERVER['REQUEST_METHOD'])) $txt.='http request method: '.$_SERVER['REQUEST_METHOD']."\n";
+ if(isset($_SERVER['REQUEST_URI'])) $txt.='http request uri: '.$_SERVER['REQUEST_URI']."\n";
+ if(isset($_GET)) foreach($_GET as $key=>$value) $txt.='get parameter: '.$key.'->'.$value."\n";
+ if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n";
+ return($txt);
+ }
+
+ /**
+ * checks if the user is authenticated
+ * checks the IP whitlist, apikeys and login/password combination
+ * if $forceuser is true and the authentication failed it returns an 401 http response.
+ * if $forceuser is false and authentification fails it returns an empty username string
+ * @param bool $forceuser
+ * @return username string
+ */
+ private static function checkPassword($forceuser=true) {
+ //valid user account ?
+ if(isset($_SERVER['PHP_AUTH_USER'])) $authuser=$_SERVER['PHP_AUTH_USER']; else $authuser='';
+ if(isset($_SERVER['PHP_AUTH_PW'])) $authpw=$_SERVER['PHP_AUTH_PW']; else $authpw='';
+
+ if(empty($authuser)) {
+ if($forceuser){
+ header('WWW-Authenticate: Basic realm="your valid user account or api key"');
+ header('HTTP/1.0 401 Unauthorized');
+ exit;
+ }else{
+ $identifieduser='';
+ }
+ }else{
+ if(!OC_User::login($authuser,$authpw)){
+ if($forceuser){
+ header('WWW-Authenticate: Basic realm="your valid user account or api key"');
+ header('HTTP/1.0 401 Unauthorized');
+ exit;
+ }else{
+ $identifieduser='';
+ }
+ }else{
+ $identifieduser=$authuser;
+ }
+ }
+
+ return($identifieduser);
+ }
+
+
+ /**
+ * generates the xml or json response for the API call from an multidimenional data array.
+ * @param string $format
+ * @param string $status
+ * @param string $statuscode
+ * @param string $message
+ * @param array $data
+ * @param string $tag
+ * @param string $tagattribute
+ * @param int $dimension
+ * @param int $itemscount
+ * @param int $itemsperpage
+ * @return string xml/json
+ */
+ private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
+ if($format=='json') {
+ $json=array();
+ $json['status']=$status;
+ $json['statuscode']=$statuscode;
+ $json['message']=$message;
+ $json['totalitems']=$itemscount;
+ $json['itemsperpage']=$itemsperpage;
+ $json['data']=$data;
+ return(json_encode($json));
+ }else{
+ $txt='';
+ $writer = xmlwriter_open_memory();
+ xmlwriter_set_indent( $writer, 2 );
+ xmlwriter_start_document($writer );
+ xmlwriter_start_element($writer,'ocs');
+ xmlwriter_start_element($writer,'meta');
+ xmlwriter_write_element($writer,'status',$status);
+ xmlwriter_write_element($writer,'statuscode',$statuscode);
+ xmlwriter_write_element($writer,'message',$message);
+ if($itemscount<>'') xmlwriter_write_element($writer,'totalitems',$itemscount);
+ if(!empty($itemsperpage)) xmlwriter_write_element($writer,'itemsperpage',$itemsperpage);
+ xmlwriter_end_element($writer);
+ if($dimension=='0') {
+ // 0 dimensions
+ xmlwriter_write_element($writer,'data',$data);
+
+ }elseif($dimension=='1') {
+ xmlwriter_start_element($writer,'data');
+ foreach($data as $key=>$entry) {
+ xmlwriter_write_element($writer,$key,$entry);
+ }
+ xmlwriter_end_element($writer);
+
+ }elseif($dimension=='2') {
+ xmlwriter_start_element($writer,'data');
+ foreach($data as $entry) {
+ xmlwriter_start_element($writer,$tag);
+ if(!empty($tagattribute)) {
+ xmlwriter_write_attribute($writer,'details',$tagattribute);
+ }
+ foreach($entry as $key=>$value) {
+ if(is_array($value)){
+ foreach($value as $k=>$v) {
+ xmlwriter_write_element($writer,$k,$v);
+ }
+ } else {
+ xmlwriter_write_element($writer,$key,$value);
+ }
+ }
+ xmlwriter_end_element($writer);
+ }
+ xmlwriter_end_element($writer);
+
+ }elseif($dimension=='3') {
+ xmlwriter_start_element($writer,'data');
+ foreach($data as $entrykey=>$entry) {
+ xmlwriter_start_element($writer,$tag);
+ if(!empty($tagattribute)) {
+ xmlwriter_write_attribute($writer,'details',$tagattribute);
+ }
+ foreach($entry as $key=>$value) {
+ if(is_array($value)){
+ xmlwriter_start_element($writer,$entrykey);
+ foreach($value as $k=>$v) {
+ xmlwriter_write_element($writer,$k,$v);
+ }
+ xmlwriter_end_element($writer);
+ } else {
+ xmlwriter_write_element($writer,$key,$value);
+ }
+ }
+ xmlwriter_end_element($writer);
+ }
+ xmlwriter_end_element($writer);
+ }elseif($dimension=='dynamic') {
+ xmlwriter_start_element($writer,'data');
+ OC_OCS::toxml($writer,$data,'comment');
+ xmlwriter_end_element($writer);
+ }
+
+ xmlwriter_end_element($writer);
+
+ xmlwriter_end_document( $writer );
+ $txt.=xmlwriter_output_memory( $writer );
+ unset($writer);
+ return($txt);
+ }
+ }
+
+ public static function toXml($writer,$data,$node) {
+ foreach($data as $key => $value) {
+ if (is_numeric($key)) {
+ $key = $node;
+ }
+ if (is_array($value)){
+ xmlwriter_start_element($writer,$key);
+ OC_OCS::toxml($writer,$value,$node);
+ xmlwriter_end_element($writer);
+ }else{
+ xmlwriter_write_element($writer,$key,$value);
+ }
+ }
+ }
+
+
+
+
+ /**
+ * return the config data of this server
+ * @param string $format
+ * @return string xml/json
+ */
+ public static function apiConfig($parameters) {
+ $format = $parameters['format'];
+ $user=OC_OCS::checkpassword(false);
+ $url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'],0,-11).'';
+
+ $xml['version']='1.7';
+ $xml['website']='ownCloud';
+ $xml['host']=OCP\Util::getServerHost();
+ $xml['contact']='';
+ $xml['ssl']='false';
+ echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'config','',1));
+ }
+
+
+ /**
+ * check if the provided login/apikey/password is valid
+ * @param string $format
+ * @param string $login
+ * @param string $passwd
+ * @return string xml/json
+ */
+ private static function personCheck($format,$login,$passwd) {
+ if($login<>''){
+ if(OC_User::login($login,$passwd)){
+ $xml['person']['personid']=$login;
+ echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'person','check',2));
+ }else{
+ echo(OC_OCS::generatexml($format,'failed',102,'login not valid'));
+ }
+ }else{
+ echo(OC_OCS::generatexml($format,'failed',101,'please specify all mandatory fields'));
+ }
+ }
+
+
+
+ // ACTIVITY API #############################################
+
+ /**
+ * get my activities
+ * @param string $format
+ * @param string $page
+ * @param string $pagesize
+ * @return string xml/json
+ */
+ private static function activityGet($format,$page,$pagesize) {
+ $user=OC_OCS::checkpassword();
+
+ //TODO
+
+ $txt=OC_OCS::generatexml($format,'ok',100,'',$xml,'activity','full',2,$totalcount,$pagesize);
+ echo($txt);
+ }
+
+ /**
+ * submit a activity
+ * @param string $format
+ * @param string $message
+ * @return string xml/json
+ */
+ private static function activityPut($format,$message) {
+ // not implemented in ownCloud
+ $user=OC_OCS::checkpassword();
+ echo(OC_OCS::generatexml($format,'ok',100,''));
+ }
+
+ // PRIVATEDATA API #############################################
+
+ /**
+ * get private data and create the xml for ocs
+ * @param string $format
+ * @param string $app
+ * @param string $key
+ * @return string xml/json
+ */
+ private static function privateDataGet($format,$app="",$key="") {
+ $user=OC_OCS::checkpassword();
+ $result=OC_OCS::getData($user,$app,$key);
+ $xml=array();
+ foreach($result as $i=>$log) {
+ $xml[$i]['key']=$log['key'];
+ $xml[$i]['app']=$log['app'];
+ $xml[$i]['value']=$log['value'];
+ }
+
+
+ $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'privatedata', 'full', 2, count($xml), 0);//TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it
+ echo($txt);
+ }
+
+ /**
+ * set private data referenced by $key to $value and generate the xml for ocs
+ * @param string $format
+ * @param string $app
+ * @param string $key
+ * @param string $value
+ * @return string xml/json
+ */
private static function privateDataSet($format, $app, $key, $value) {
$user=OC_OCS::checkpassword();
if(OC_OCS::setData($user,$app,$key,$value)){
@@ -529,4 +576,71 @@ class OC_OCS {
public static function deleteData($user, $app, $key) {
return OC_Preferences::deleteKey($user,$app,$key);
}
+
+
+ // CLOUD API #############################################
+
+ /**
+ * get the quota of a user
+ * @param string $format
+ * @param string $user
+ * @return string xml/json
+ */
+ private static function quotaGet($format,$user) {
+ $login=OC_OCS::checkpassword();
+ if(OC_Group::inGroup($login, 'admin') or ($login==$user)) {
+
+ if(OC_User::userExists($user)){
+ // calculate the disc space
+ $user_dir = '/'.$user.'/files';
+ OC_Filesystem::init($user_dir);
+ $rootInfo=OC_FileCache::get('');
+ $sharedInfo=OC_FileCache::get('/Shared');
+ $used=$rootInfo['size']-$sharedInfo['size'];
+ $free=OC_Filesystem::free_space();
+ $total=$free+$used;
+ if($total==0) $total=1; // prevent division by zero
+ $relative=round(($used/$total)*10000)/100;
+
+ $xml=array();
+ $xml['quota']=$total;
+ $xml['free']=$free;
+ $xml['used']=$used;
+ $xml['relative']=$relative;
+
+ $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'cloud', 'full', 1, count($xml), 0);
+ echo($txt);
+ }else{
+ echo self::generateXml('', 'fail', 300, 'User does not exist');
+ }
+ }else{
+ echo self::generateXml('', 'fail', 300, 'You don´t have permission to access this ressource.');
+ }
+ }
+
+ /**
+ * set the quota of a user
+ * @param string $format
+ * @param string $user
+ * @param string $quota
+ * @return string xml/json
+ */
+ private static function quotaSet($format,$user,$quota) {
+ $login=OC_OCS::checkpassword();
+ if(OC_Group::inGroup($login, 'admin')) {
+
+ // todo
+ // not yet implemented
+ // edit logic here
+ error_log('OCS call: user:'.$user.' quota:'.$quota);
+
+ $xml=array();
+ $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'cloud', 'full', 1, count($xml), 0);
+ echo($txt);
+ }else{
+ echo self::generateXml('', 'fail', 300, 'You don´t have permission to access this ressource.');
+ }
+ }
+
+
}
diff --git a/lib/user.php b/lib/user.php
index 356be4decf9..549319b3a77 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -104,11 +104,17 @@ class OC_User {
break;
}
}
-
true;
}
/**
+ * remove all used backends
+ */
+ public static function clearBackends(){
+ self::$_usedBackends=array();
+ }
+
+ /**
* @brief Create a new user
* @param $uid The username of the user to create
* @param $password The password of the new user
diff --git a/lib/util.php b/lib/util.php
index f35e5a18e42..0c563278cc5 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -77,13 +77,13 @@ class OC_Util {
return '5 pre alpha';
}
- /**
- * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise".
- * @return string
- */
- public static function getEditionString(){
- return '';
- }
+ /**
+ * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise".
+ * @return string
+ */
+ public static function getEditionString(){
+ return '';
+ }
/**
* add a javascript file
@@ -131,12 +131,12 @@ class OC_Util {
self::$headers[]=array('tag'=>$tag,'attributes'=>$attributes,'text'=>$text);
}
- /**
- * formats a timestamp in the "right" way
- *
- * @param int timestamp $timestamp
- * @param bool dateOnly option to ommit time from the result
- */
+ /**
+ * formats a timestamp in the "right" way
+ *
+ * @param int timestamp $timestamp
+ * @param bool dateOnly option to ommit time from the result
+ */
public static function formatDate( $timestamp,$dateOnly=false){
if(isset($_SESSION['timezone'])){//adjust to clients timezone if we know it
$systemTimeZone = intval(date('O'));
@@ -438,26 +438,25 @@ class OC_Util {
}
- /**
- * Check if the htaccess file is working by creating a test file in the data directory and trying to access via http
- */
- public static function ishtaccessworking() {
-
+ /**
+ * Check if the htaccess file is working by creating a test file in the data directory and trying to access via http
+ */
+ public static function ishtaccessworking() {
// testdata
$filename='/htaccesstest.txt';
$testcontent='testcontent';
// creating a test file
- $testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename;
- $fp = @fopen($testfile, 'w');
- @fwrite($fp, $testcontent);
- @fclose($fp);
+ $testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename;
+ $fp = @fopen($testfile, 'w');
+ @fwrite($fp, $testcontent);
+ @fclose($fp);
// accessing the file via http
- $url = OC_Helper::serverProtocol(). '://' . OC_Helper::serverHost() . OC::$WEBROOT.'/data'.$filename;
- $fp = @fopen($url, 'r');
- $content=@fread($fp, 2048);
- @fclose($fp);
+ $url = OC_Helper::serverProtocol(). '://' . OC_Helper::serverHost() . OC::$WEBROOT.'/data'.$filename;
+ $fp = @fopen($url, 'r');
+ $content=@fread($fp, 2048);
+ @fclose($fp);
// cleanup
@unlink($testfile);
@@ -467,13 +466,7 @@ class OC_Util {
return(false);
}else{
return(true);
-
}
-
- }
-
-
-
-
+ }
}
diff --git a/ocs/providers.php b/ocs/providers.php
index f9cafd20b01..cc6de32266b 100644
--- a/ocs/providers.php
+++ b/ocs/providers.php
@@ -35,7 +35,9 @@ echo('
<termsofuse></termsofuse>
<register></register>
<services>
- <activity ocsversion="1.5" />
+ <config ocsversion="1.7" />
+ <activity ocsversion="1.7" />
+ <cloud ocsversion="1.7" />
</services>
</provider>
</providers>
diff --git a/tests/lib/cache.php b/tests/lib/cache.php
index bb5cfc6ee19..511999be956 100644
--- a/tests/lib/cache.php
+++ b/tests/lib/cache.php
@@ -42,6 +42,27 @@ abstract class Test_Cache extends UnitTestCase {
$this->assertNull($this->instance->get('not_set'),'Unset value not equal to null');
$this->assertTrue($this->instance->remove('value1'));
+ $this->assertFalse($this->instance->hasKey('value1'));
+ }
+
+ function testClear(){
+ $value='ipsum lorum';
+ $this->instance->set('1_value1',$value);
+ $this->instance->set('1_value2',$value);
+ $this->instance->set('2_value1',$value);
+ $this->instance->set('3_value1',$value);
+
+ $this->assertTrue($this->instance->clear('1_'));
+ $this->assertFalse($this->instance->hasKey('1_value1'));
+ $this->assertFalse($this->instance->hasKey('1_value2'));
+ $this->assertTrue($this->instance->hasKey('2_value1'));
+ $this->assertTrue($this->instance->hasKey('3_value1'));
+
+ $this->assertTrue($this->instance->clear());
+ $this->assertFalse($this->instance->hasKey('1_value1'));
+ $this->assertFalse($this->instance->hasKey('1_value2'));
+ $this->assertFalse($this->instance->hasKey('2_value1'));
+ $this->assertFalse($this->instance->hasKey('3_value1'));
}
function testTTL(){
diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php
index c33c513fcff..28778efb68c 100644
--- a/tests/lib/cache/file.php
+++ b/tests/lib/cache/file.php
@@ -21,8 +21,10 @@
*/
class Test_Cache_File extends Test_Cache {
+ private $user;
+
function skip() {
- $this->skipUnless(OC_User::isLoggedIn());
+ //$this->skipUnless(OC_User::isLoggedIn());
}
public function setUp(){
@@ -39,10 +41,23 @@ class Test_Cache_File extends Test_Cache {
OC_Filesystem::clearMounts();
OC_Filesystem::mount('OC_Filestorage_Temporary',array(),'/');
+ OC_User::clearBackends();
+ OC_User::useBackend(new OC_User_Dummy());
+
+ //login
+ OC_User::createUser('test', 'test');
+
+ $this->user=OC_User::getUser();
+ OC_User::setUserId('test');
+
//set up the users dir
$rootView=new OC_FilesystemView('');
- $rootView->mkdir('/'.OC_User::getUser());
+ $rootView->mkdir('/test');
$this->instance=new OC_Cache_File();
}
+
+ public function tearDown(){
+ OC_User::setUserId($this->user);
+ }
}