Monotone-Parent: 8d5e1ecd9bc18e87c532bd2afcb12d16f9f0b19a
Monotone-Revision: 9ae88bb6243ba87ed733deacf0d14abf74a4cb60 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2007-10-02T22:03:27 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
97cae93278
commit
622fdf3bae
|
@ -0,0 +1,482 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, 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 library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, 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 companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,4 @@
|
|||
Copyright (C) 2004 SKYRIX Software AG
|
||||
|
||||
|
||||
Contact: info@skyrix.com
|
|
@ -0,0 +1,329 @@
|
|||
2007-08-29 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* EOQualifier+GCS.m: rewrote comparison code, now uses UPPER instead of
|
||||
the PostgreSQL specific ILIKE. Fixes OGo bug #1906 (v4.7.49)
|
||||
|
||||
2007-07-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added 'some' rollback after an error (v4.7.48)
|
||||
|
||||
2007-07-20 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolderManager.m: fixed a bug in last check, DROP TABLE is allowed
|
||||
to fail in the given context (bug #1883) (v4.7.47)
|
||||
|
||||
2007-07-11 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added some error checking, plenty of open ends
|
||||
pending (eg folder creation not wrapped in a transaction) (v4.7.46)
|
||||
|
||||
2007-06-29 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolderManager.m: fixed folder creation to populate empty path
|
||||
fields with NULLs (OGo bug #1883) (v4.7.45)
|
||||
|
||||
2007-04-25 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm]: added methods to delete ACL records (OGo bug #1866)
|
||||
(v4.7.44)
|
||||
|
||||
2007-04-22 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSChannelManager.m: improved error log (v4.7.43)
|
||||
|
||||
2007-04-17 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed a few GNUstep compilation warnings (v4.7.42)
|
||||
|
||||
2007-03-21 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm], GCSFolderManager.[hm]: added ability to create and
|
||||
delete GCS folders programmatically (OGo bug #1850) (v4.7.41)
|
||||
|
||||
2007-02-12 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolder.m: fixed a gnustep-base compilation warning (v4.7.40)
|
||||
|
||||
2007-02-09 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* use -errorWithFormat:, fixed a few logging crashes (incomplete format
|
||||
strings) (v4.5.39)
|
||||
|
||||
2007-02-08 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.m: added a gnustep-base hack to properly format bool
|
||||
numbers for SQL. Base returns YES or NO in -stringValue while
|
||||
libFoundation/NGExt returns 0 or 1 (v4.5.39)
|
||||
|
||||
2007-01-15 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm], GCSFolderManager.m: added support for content table
|
||||
ACLs (v4.5.38)
|
||||
|
||||
2006-08-31 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* EOQualifier+GCS.m: added support for OR qualifiers and for case
|
||||
insensitive-like qualifiers on PostgreSQL (v4.5.37)
|
||||
|
||||
2006-07-04 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.36)
|
||||
|
||||
2005-08-16 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GNUmakefile, GNUmakefile.preamble: added OSX framework compilation
|
||||
(v4.5.35)
|
||||
|
||||
2005-07-23 Sebastian Reitenbach <reitenbach@rapideye.de>
|
||||
|
||||
* GNUmakefile.preamble: added OpenBSD linking flags (v4.5.34)
|
||||
|
||||
2005-07-13 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolder.h: added -versionOfContentWithName: method to header file
|
||||
(v4.5.33)
|
||||
|
||||
* GCSFolder.m: return a proper exception if the extractor was unable to
|
||||
create a quickrow for a given content object (v4.5.32)
|
||||
|
||||
* GCSFolder.m: added -writeContent:toName:baseVersion: to support
|
||||
consistent update operations (eg using etags), properly increase
|
||||
content object version on update operations (v4.5.31)
|
||||
|
||||
* GCSFolderManager.m, GCSFolder.m: changed not to use EOF
|
||||
attribute-name 'beautification', eg 'c_name' will stay 'c_name'
|
||||
instead of being transformed into 'cName' (v4.5.30)
|
||||
|
||||
2005-07-11 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added automatic discovery of folder types by
|
||||
scanning for .ocs files (v4.5.29)
|
||||
|
||||
2005-04-25 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed gcc 4.0 warnings (v4.5.28)
|
||||
|
||||
2005-03-21 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* GNUmakefile: added FHS support (v4.5.27)
|
||||
|
||||
2005-03-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* moved OGoContentStore as GDLContentStore into sope-gdl1, removed
|
||||
dependencies on NGiCal and removed some SOGo specific things
|
||||
(v4.5.26)
|
||||
|
||||
2005-03-07 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* appointment.ocs: added missing 'partstates' field (v0.9.25)
|
||||
|
||||
2005-03-04 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* v0.9.24
|
||||
|
||||
* ocs_gensql.m: started tool to create SQL CREATE from ocs model file
|
||||
|
||||
* OCSFolderType.m: small change to the factory API, changed to use
|
||||
NGResourceLocator
|
||||
|
||||
2005-03-03 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolderManager.m: fixed a bug in subfolder listing (v0.9.23)
|
||||
|
||||
2005-03-01 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.22
|
||||
|
||||
* appointment.ocs: added 'cycleenddate' and 'cycleinfo' to address
|
||||
previous performance issues
|
||||
|
||||
* OCSiCalFieldExtractor.m: set 'cycleenddate' and 'cycleinfo' for
|
||||
recurrent events. Reverted setting of 'enddate' to the previous
|
||||
behaviour since 'cycleenddate' is dedicated to the task now
|
||||
|
||||
* iCalRepeatableEntityObject+OCS.[hm]: new category used by the
|
||||
OCSiCalFieldExtractor to extract cycleInfo in an appropriate format
|
||||
|
||||
* sql/generate-folderinfo-sql-for-users.sh,
|
||||
sql/foldertablecreate-helge-privcal.psql,
|
||||
sql/foldertablecreate-helge-privcal.sqlite,
|
||||
sql/generate-folderinfo-sql-for-users-sqlite.sh: adjusted to new
|
||||
schema
|
||||
|
||||
2005-03-01 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolder.m: added support for storing content and quick info in
|
||||
the same table (untested) (v0.9.21)
|
||||
|
||||
2005-02-21 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* v0.9.20
|
||||
|
||||
* OCSFolderManager.m: removed quoting of SQL table and column names
|
||||
(breaks with SQLite and isn't necessary for PG), fixed URL pooling
|
||||
for SQLite
|
||||
|
||||
* NSURL+OCS.m: use tablename for last path component
|
||||
|
||||
2005-02-12 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSiCalFieldExtractor.m: uses new iCalEvent API to determine correct
|
||||
'enddate' for recurrent events. This is an optimization which can
|
||||
save quite some time for complex rules. (v0.9.19)
|
||||
|
||||
2004-12-17 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.18
|
||||
|
||||
* OCSiCalFieldExtractor.m: extract participants' state
|
||||
|
||||
* sql/generate-folderinfo-sql-for-user.sh, sql/appointment-create.psql,
|
||||
sql/foldertablecreate-helge-privcal.psql: updated with new schema.
|
||||
|
||||
2004-12-15 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSiCalFieldExtractor.m: partmails + cn's are concatenated by '\n'
|
||||
now - this directly eliminates any ambiguities. Also, instead of
|
||||
using 'email' for partmails and orgmail, the extractor uses the
|
||||
'rfc822Email' value which strips away any preceeding 'mailto:'
|
||||
prefix, compacting the representation and speeding up comparison.
|
||||
Also, "iscycle", "isallday" and "isopaque" are now provided by
|
||||
NGiCal and thus always extracted (v0.9.17)
|
||||
|
||||
2004-12-13 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* sql/generate-folderinfo-sql-for-user.sh: fixed critical error in
|
||||
Contacts folder_info, type was 'Appointment' but MUST be 'Contact'
|
||||
(v0.9.16)
|
||||
|
||||
2004-12-10 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* sql: updated all generation scripts to the latest version (v0.9.15)
|
||||
|
||||
2004-12-09 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.14
|
||||
|
||||
* appointment.ocs: added "ispublic", "isopaque", "status" and
|
||||
"orgmail".
|
||||
|
||||
* OCSiCalFieldExtractor.m: updated to extract new fields (see above)
|
||||
|
||||
* sql: updated generate-folderinfo-sql-for-users.sh
|
||||
|
||||
2004-10-19 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolder.m: added new method -fetchContentsOfAllFiles method which
|
||||
fetches the contents of all files stored in the folder (required for
|
||||
iCal generation, such bulk fetches should be avoided if possible!)
|
||||
(v0.9.13)
|
||||
|
||||
2004-10-15 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSStringFormatter.[hm]: minor cleanup (v0.9.12)
|
||||
|
||||
* v0.9.11
|
||||
|
||||
* OCSStringFormatter.[hm]: new class to format strings according to
|
||||
Database requirements (escaping etc.).
|
||||
|
||||
* OCSFolder.m: uses new OCSStringFormatter now.
|
||||
|
||||
2004-09-25 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed compilation on MacOSX (v0.9.10)
|
||||
|
||||
2004-09-10 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.9
|
||||
|
||||
* fixed some gcc warnings
|
||||
|
||||
* GNUmakefile.preamble: added pathes to compile against an FHS SOPE
|
||||
|
||||
* OCSiCalFieldExtractor.m: fixed type of sequence iCalEvent field
|
||||
|
||||
2004-09-01 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* GNUmakefile: install type models into $(GNUSTEP_USER_ROOT) (v0.9.8)
|
||||
|
||||
2004-08-27 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.7
|
||||
|
||||
* OCSChannelManager.m: use PostgreSQL as adaptor, not PostgreSQL72
|
||||
|
||||
* OCSFolder.m: added support for doing folder sorting in SQL
|
||||
|
||||
2004-08-26 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.6
|
||||
|
||||
* added OCSContactFieldExtractor
|
||||
|
||||
* sql: added sample contact folder create scripts
|
||||
|
||||
* OCSFolderType.m: read extractor class name from type model
|
||||
|
||||
* OCSFolderManager.m: added contact type model per default (v0.9.5)
|
||||
|
||||
2004-08-25 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* GNUmakefile: automatically install OCSTypeModels (v0.9.4)
|
||||
|
||||
2004-08-15 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* OCSFolder.m: added content deletion (v0.9.3)
|
||||
|
||||
* OCSFolder.m: added sanity check to store method (v0.9.2)
|
||||
|
||||
2004-08-14 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.1
|
||||
|
||||
* OCSiCalFieldExtractor.m: extract new quick fields: location,
|
||||
partmails, sequence (does not yet handle allday and cycle due to
|
||||
NGiCal restrictions)
|
||||
|
||||
* appointment.ocs, sql/foldertablecreate-helge-privcal.psql,
|
||||
sql/testapt-agenor-helge-privcal.psql, sql/appointment-create.psql:
|
||||
added quick fields: isallday, iscycle, location, partmails, sequence
|
||||
|
||||
* started ocs_recreatequick tool intended for recreating a quick table
|
||||
based on the content table of a folder
|
||||
|
||||
2004-07-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: fixed a bug in the channel GC which resulted
|
||||
in an exception during the GC NSTimer
|
||||
|
||||
2004-07-16 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* improved error handling in various files
|
||||
|
||||
2004-07-02 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: added garbage collector for channel pools
|
||||
|
||||
2004-06-30 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: implemented pooling
|
||||
|
||||
* OCSFolder.m: added quick fetches
|
||||
|
||||
* GNUmakefile.preamble: fix link path
|
||||
|
||||
* GNUmakefile (libOGoContentStore_HEADER_FILES_INSTALL_DIR): install
|
||||
headers in OGoContentStore
|
||||
|
||||
* GNUmakefile.preamble (ocs_ls_TOOL_LIBS): added static dependencies
|
||||
for OSX
|
||||
|
||||
2004-06-30 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* ocs_cat.m, ocs_ls.m, ocs_mkdir.m: fixed for gnustep compile.
|
||||
|
||||
2004-06-29 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* created ChangeLog
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_EOAdaptorChannel_GCS_H__
|
||||
#define __GDLContentStore_EOAdaptorChannel_GCS_H__
|
||||
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
|
||||
@protocol GCSEOAdaptorChannel
|
||||
|
||||
- (NSException *) createGCSFolderTableWithName: (NSString *) tableName;
|
||||
- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName;
|
||||
|
||||
@end
|
||||
|
||||
@interface EOAdaptorChannel(GCS)
|
||||
|
||||
- (BOOL)tableExistsWithName:(NSString *)_tableName;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_EOAdaptorChannel_GCS_H__ */
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation EOAdaptorChannel(GCS)
|
||||
|
||||
- (BOOL)tableExistsWithName:(NSString *)_tableName {
|
||||
NSException *ex;
|
||||
NSString *sql;
|
||||
BOOL didOpen;
|
||||
|
||||
didOpen = NO;
|
||||
if (![self isOpen]) {
|
||||
if (![self openChannel])
|
||||
return NO;
|
||||
didOpen = YES;
|
||||
}
|
||||
|
||||
sql = @"SELECT COUNT(*) FROM ";
|
||||
sql = [sql stringByAppendingString:_tableName];
|
||||
sql = [sql stringByAppendingString:@" WHERE 1 = 2"];
|
||||
|
||||
ex = [[[self evaluateExpressionX:sql] retain] autorelease];
|
||||
[self cancelFetch];
|
||||
|
||||
if (didOpen) [self closeChannel];
|
||||
return ex != nil ? NO : YES;
|
||||
}
|
||||
|
||||
@end /* EOAdaptorChannel(GCS) */
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_EOQualifier_GCS_H__
|
||||
#define __GDLContentStore_EOQualifier_GCS_H__
|
||||
|
||||
#include <EOControl/EOQualifier.h>
|
||||
|
||||
@class NSMutableString;
|
||||
|
||||
@interface EOQualifier(GCS)
|
||||
|
||||
- (void)_gcsAppendToString:(NSMutableString *)_ms;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_EOQualifier_GCS_H__ */
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "EOQualifier+GCS.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation EOQualifier(GCS)
|
||||
|
||||
- (void)_appendAndQualifier:(EOAndQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
// TODO: move to EOQualifier category
|
||||
NSArray *qs;
|
||||
unsigned i, count;
|
||||
|
||||
qs = [_q qualifiers];
|
||||
if ((count = [qs count]) == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i != 0) [_ms appendString:@" AND "];
|
||||
if (count > 1) [_ms appendString:@"("];
|
||||
[[qs objectAtIndex:i] _gcsAppendToString:_ms];
|
||||
if (count > 1) [_ms appendString:@")"];
|
||||
}
|
||||
}
|
||||
- (void)_appendOrQualifier:(EOAndQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
// TODO: move to EOQualifier category
|
||||
NSArray *qs;
|
||||
unsigned i, count;
|
||||
|
||||
qs = [_q qualifiers];
|
||||
if ((count = [qs count]) == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i != 0) [_ms appendString:@" OR "];
|
||||
if (count > 1) [_ms appendString:@"("];
|
||||
[[qs objectAtIndex:i] _gcsAppendToString:_ms];
|
||||
if (count > 1) [_ms appendString:@")"];
|
||||
}
|
||||
}
|
||||
- (void)_appendKeyValueQualifier:(EOKeyValueQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
id val;
|
||||
NSString *qKey, *qOperator, *qValue, *qFormat;
|
||||
BOOL isCI;
|
||||
|
||||
qKey = [_q key];
|
||||
|
||||
if ((val = [_q value])) {
|
||||
SEL op = [_q selector];
|
||||
|
||||
if ([val isNotNull]) {
|
||||
isCI = NO;
|
||||
|
||||
if (sel_eq(op, EOQualifierOperatorEqual))
|
||||
qOperator = @"=";
|
||||
else if (sel_eq(op, EOQualifierOperatorNotEqual))
|
||||
qOperator = @"!=";
|
||||
else if (sel_eq(op, EOQualifierOperatorLessThan))
|
||||
qOperator = @"<";
|
||||
else if (sel_eq(op, EOQualifierOperatorGreaterThan))
|
||||
qOperator = @">";
|
||||
else if (sel_eq(op, EOQualifierOperatorLessThanOrEqualTo))
|
||||
qOperator = @"<=";
|
||||
else if (sel_eq(op, EOQualifierOperatorGreaterThanOrEqualTo))
|
||||
qOperator = @">=";
|
||||
else if (sel_eq(op, EOQualifierOperatorLike))
|
||||
qOperator = @"LIKE";
|
||||
else if (sel_eq(op, EOQualifierOperatorCaseInsensitiveLike)) {
|
||||
isCI = YES;
|
||||
qOperator = @"LIKE";
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: unsupported operation for null: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromSelector(op)];
|
||||
}
|
||||
|
||||
if ([val isKindOfClass:[NSNumber class]])
|
||||
qValue = [val stringValue];
|
||||
else if ([val isKindOfClass:[NSString class]]) {
|
||||
qValue = [NSString stringWithFormat: @"'%@'", val];
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: unsupported value class: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromClass([val class])];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sel_eq(op, EOQualifierOperatorEqual)) {
|
||||
qOperator = @"IS";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
else if (sel_eq(op, EOQualifierOperatorEqual)) {
|
||||
qOperator = @"IS NOT";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: invalid operation for null: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromSelector(op)];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qOperator = @"IS";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
|
||||
if (isCI)
|
||||
qFormat = @"UPPER(%@) %@ UPPER(%@)";
|
||||
else
|
||||
qFormat = @"%@ %@ %@";
|
||||
|
||||
[_ms appendFormat: qFormat, qKey, qOperator, qValue];
|
||||
}
|
||||
|
||||
- (void)_appendQualifier:(EOQualifier *)_q toString:(NSMutableString *)_ms {
|
||||
if (_q == nil) return;
|
||||
|
||||
if ([_q isKindOfClass:[EOAndQualifier class]])
|
||||
[self _appendAndQualifier:(id)_q toString:_ms];
|
||||
else if ([_q isKindOfClass:[EOOrQualifier class]])
|
||||
[self _appendOrQualifier:(id)_q toString:_ms];
|
||||
else if ([_q isKindOfClass:[EOKeyValueQualifier class]])
|
||||
[self _appendKeyValueQualifier:(id)_q toString:_ms];
|
||||
else
|
||||
[self errorWithFormat:@"unknown qualifier: %@", _q];
|
||||
}
|
||||
|
||||
- (void)_gcsAppendToString:(NSMutableString *)_ms {
|
||||
[self _appendQualifier:self toString:_ms];
|
||||
}
|
||||
|
||||
@end /* EOQualifier(GCS) */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSChannelManager_H__
|
||||
#define __GDLContentStore_GCSChannelManager_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSChannelManager
|
||||
|
||||
This object manages the connection pooling.
|
||||
*/
|
||||
|
||||
@class NSURL, NSMutableDictionary, NSMutableArray, NSTimer;
|
||||
@class EOAdaptorChannel, EOAdaptor;
|
||||
|
||||
@interface GCSChannelManager : NSObject
|
||||
{
|
||||
NSMutableDictionary *urlToAdaptor;
|
||||
|
||||
NSMutableArray *availableChannels;
|
||||
NSMutableArray *busyChannels;
|
||||
NSTimer *gcTimer;
|
||||
}
|
||||
|
||||
+ (id)defaultChannelManager;
|
||||
|
||||
/* channels */
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannelForURL:(NSURL *)_url;
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel;
|
||||
|
||||
/* checking for tables */
|
||||
|
||||
- (BOOL)canConnect:(NSURL *)_url;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSChannelManager_H__ */
|
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSChannelManager.h"
|
||||
#include "NSURL+GCS.h"
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include <GDLAccess/EOAdaptor.h>
|
||||
#include <GDLAccess/EOAdaptorContext.h>
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- implemented pooling
|
||||
- auto-close channels which are very old?!
|
||||
(eg missing release due to an exception)
|
||||
*/
|
||||
|
||||
@interface GCSChannelHandle : NSObject
|
||||
{
|
||||
@public
|
||||
NSURL *url;
|
||||
EOAdaptorChannel *channel;
|
||||
NSDate *creationTime;
|
||||
NSDate *lastReleaseTime;
|
||||
NSDate *lastAcquireTime;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)channel;
|
||||
- (BOOL)canHandleURL:(NSURL *)_url;
|
||||
- (NSTimeInterval)age;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GCSChannelManager
|
||||
|
||||
static BOOL debugOn = NO;
|
||||
static BOOL debugPools = NO;
|
||||
static int ChannelExpireAge = 180;
|
||||
static NSTimeInterval ChannelCollectionTimer = 5 * 60;
|
||||
|
||||
+ (void)initialize {
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
debugOn = [ud boolForKey:@"GCSChannelManagerDebugEnabled"];
|
||||
debugPools = [ud boolForKey:@"GCSChannelManagerPoolDebugEnabled"];
|
||||
|
||||
ChannelExpireAge = [[ud objectForKey:@"GCSChannelExpireAge"] intValue];
|
||||
if (ChannelExpireAge < 1)
|
||||
ChannelExpireAge = 180;
|
||||
|
||||
ChannelCollectionTimer =
|
||||
[[ud objectForKey:@"GCSChannelCollectionTimer"] intValue];
|
||||
if (ChannelCollectionTimer < 1)
|
||||
ChannelCollectionTimer = 5*60;
|
||||
}
|
||||
|
||||
+ (NSString *)adaptorNameForURLScheme:(NSString *)_scheme {
|
||||
// TODO: map scheme to adaptors (eg 'postgresql://' to PostgreSQL
|
||||
return @"PostgreSQL";
|
||||
}
|
||||
|
||||
+ (id)defaultChannelManager {
|
||||
static GCSChannelManager *cm = nil;
|
||||
if (cm == nil)
|
||||
cm = [[self alloc] init];
|
||||
return cm;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->urlToAdaptor = [[NSMutableDictionary alloc] initWithCapacity:4];
|
||||
self->availableChannels = [[NSMutableArray alloc] initWithCapacity:16];
|
||||
self->busyChannels = [[NSMutableArray alloc] initWithCapacity:16];
|
||||
|
||||
self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
|
||||
ChannelCollectionTimer
|
||||
target:self selector:@selector(_garbageCollect:)
|
||||
userInfo:nil repeats:YES] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (self->gcTimer) [self->gcTimer invalidate];
|
||||
[self->gcTimer release];
|
||||
|
||||
[self->busyChannels release];
|
||||
[self->availableChannels release];
|
||||
[self->urlToAdaptor release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* DB key */
|
||||
|
||||
- (NSString *)databaseKeyForURL:(NSURL *)_url {
|
||||
/*
|
||||
We need to build a proper key that omits passwords and URL path components
|
||||
which are not required.
|
||||
*/
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat:@"%@\n%@\n%@\n%@",
|
||||
[_url host], [_url port],
|
||||
[_url user], [_url gcsDatabaseName]];
|
||||
return key;
|
||||
}
|
||||
|
||||
/* adaptors */
|
||||
|
||||
- (NSDictionary *)connectionDictionaryForURL:(NSURL *)_url {
|
||||
NSMutableDictionary *md;
|
||||
id tmp;
|
||||
|
||||
md = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
|
||||
if ((tmp = [_url host]) != nil)
|
||||
[md setObject:tmp forKey:@"hostName"];
|
||||
if ((tmp = [_url port]) != nil)
|
||||
[md setObject:tmp forKey:@"port"];
|
||||
if ((tmp = [_url user]) != nil)
|
||||
[md setObject:tmp forKey:@"userName"];
|
||||
if ((tmp = [_url password]) != nil)
|
||||
[md setObject:tmp forKey:@"password"];
|
||||
|
||||
if ((tmp = [_url gcsDatabaseName]) != nil)
|
||||
[md setObject:tmp forKey:@"databaseName"];
|
||||
|
||||
[self debugWithFormat:@"build connection dictionary for URL %@: %@",
|
||||
[_url absoluteString], md];
|
||||
return md;
|
||||
}
|
||||
|
||||
- (EOAdaptor *)adaptorForURL:(NSURL *)_url {
|
||||
EOAdaptor *adaptor;
|
||||
NSString *key;
|
||||
|
||||
if (_url == nil)
|
||||
return nil;
|
||||
if ((key = [self databaseKeyForURL:_url]) == nil)
|
||||
return nil;
|
||||
if ((adaptor = [self->urlToAdaptor objectForKey:key]) != nil) {
|
||||
[self debugWithFormat:@"using cached adaptor: %@", adaptor];
|
||||
return adaptor; /* cached :-) */
|
||||
}
|
||||
|
||||
[self debugWithFormat:@"creating new adaptor for URL: %@", _url];
|
||||
|
||||
if ([EOAdaptor respondsToSelector:@selector(adaptorForURL:)]) {
|
||||
adaptor = [EOAdaptor adaptorForURL:_url];
|
||||
}
|
||||
else {
|
||||
NSString *adaptorName;
|
||||
NSDictionary *condict;
|
||||
|
||||
adaptorName = [[self class] adaptorNameForURLScheme:[_url scheme]];
|
||||
if ([adaptorName length] == 0) {
|
||||
[self errorWithFormat:@"cannot handle URL: %@", _url];
|
||||
return nil;
|
||||
}
|
||||
|
||||
condict = [self connectionDictionaryForURL:_url];
|
||||
|
||||
if ((adaptor = [EOAdaptor adaptorWithName:adaptorName]) == nil) {
|
||||
[self errorWithFormat:@"did not find adaptor '%@' for URL: %@",
|
||||
adaptorName, _url];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[adaptor setConnectionDictionary:condict];
|
||||
}
|
||||
|
||||
[self->urlToAdaptor setObject:adaptor forKey:key];
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
/* channels */
|
||||
|
||||
- (GCSChannelHandle *)findBusyChannelHandleForChannel:(EOAdaptorChannel *)_ch {
|
||||
NSEnumerator *e;
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
e = [self->busyChannels objectEnumerator];
|
||||
while ((handle = [e nextObject])) {
|
||||
if ([handle channel] == _ch)
|
||||
return handle;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
- (GCSChannelHandle *)findAvailChannelHandleForURL:(NSURL *)_url {
|
||||
NSEnumerator *e;
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
e = [self->availableChannels objectEnumerator];
|
||||
while ((handle = [e nextObject])) {
|
||||
if ([handle canHandleURL:_url])
|
||||
return handle;
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:@"DBPOOL: cannot use handle (%@ vs %@)",
|
||||
[_url absoluteString], [handle->url absoluteString]];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)_createChannelForURL:(NSURL *)_url {
|
||||
EOAdaptor *adaptor;
|
||||
EOAdaptorContext *adContext;
|
||||
EOAdaptorChannel *adChannel;
|
||||
|
||||
if ((adaptor = [self adaptorForURL:_url]) == nil)
|
||||
return nil;
|
||||
|
||||
if ((adContext = [adaptor createAdaptorContext]) == nil) {
|
||||
[self errorWithFormat:@"could not create adaptor context!"];
|
||||
return nil;
|
||||
}
|
||||
if ((adChannel = [adContext createAdaptorChannel]) == nil) {
|
||||
[self errorWithFormat:@"could not create adaptor channel!"];
|
||||
return nil;
|
||||
}
|
||||
return adChannel;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannelForURL:(NSURL *)_url {
|
||||
// TODO: naive implementation, add pooling!
|
||||
EOAdaptorChannel *channel;
|
||||
GCSChannelHandle *handle;
|
||||
NSCalendarDate *now;
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
|
||||
/* look for cached handles */
|
||||
|
||||
if ((handle = [self findAvailChannelHandleForURL:_url]) != nil) {
|
||||
// TODO: check age?
|
||||
[self->busyChannels addObject:handle];
|
||||
[self->availableChannels removeObject:handle];
|
||||
ASSIGN(handle->lastAcquireTime, now);
|
||||
|
||||
if (debugPools)
|
||||
[self logWithFormat:@"DBPOOL: reused cached DB channel!"];
|
||||
return [[handle channel] retain];
|
||||
}
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:@"DBPOOL: create new DB channel for URL: %@",
|
||||
[_url absoluteString]];
|
||||
}
|
||||
|
||||
/* create channel */
|
||||
|
||||
if ((channel = [self _createChannelForURL:_url]) == nil)
|
||||
return nil;
|
||||
|
||||
if ([channel isOpen])
|
||||
;
|
||||
else if (![channel openChannel]) {
|
||||
[self errorWithFormat:@"could not open channel %@ for URL: %@",
|
||||
channel, [_url absoluteString]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* create handle for channel */
|
||||
|
||||
handle = [[GCSChannelHandle alloc] init];
|
||||
handle->url = [_url retain];
|
||||
handle->channel = [channel retain];
|
||||
handle->creationTime = [now retain];
|
||||
handle->lastAcquireTime = [now retain];
|
||||
|
||||
[self->busyChannels addObject:handle];
|
||||
[handle release];
|
||||
|
||||
return [channel retain];
|
||||
}
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
if ((handle = [self findBusyChannelHandleForChannel:_channel]) != nil) {
|
||||
NSCalendarDate *now;
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
|
||||
handle = [handle retain];
|
||||
ASSIGN(handle->lastReleaseTime, now);
|
||||
|
||||
[self->busyChannels removeObject:handle];
|
||||
|
||||
if ([[handle channel] isOpen] && [handle age] < ChannelExpireAge) {
|
||||
// TODO: consider age
|
||||
[self->availableChannels addObject:handle];
|
||||
if (debugPools) {
|
||||
[self logWithFormat:
|
||||
@"DBPOOL: keeping channel (age %ds, #%d): %@",
|
||||
(int)[handle age], [self->availableChannels count],
|
||||
[handle->url absoluteString]];
|
||||
}
|
||||
[_channel release];
|
||||
[handle release];
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:
|
||||
@"DBPOOL: freeing old channel (age %ds)", (int)[handle age]];
|
||||
}
|
||||
|
||||
/* not reusing channel */
|
||||
[handle release]; handle = nil;
|
||||
}
|
||||
|
||||
if ([_channel isOpen])
|
||||
[_channel closeChannel];
|
||||
|
||||
[_channel release];
|
||||
}
|
||||
|
||||
/* checking for tables */
|
||||
|
||||
- (BOOL)canConnect:(NSURL *)_url {
|
||||
/*
|
||||
this can check for DB connect as well as for table URLs (whether a table
|
||||
exists)
|
||||
*/
|
||||
EOAdaptorChannel *channel;
|
||||
NSString *table;
|
||||
BOOL result;
|
||||
|
||||
if ((channel = [self acquireOpenChannelForURL:_url]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel: %@", _url];
|
||||
return NO;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
result = YES; /* could open channel */
|
||||
|
||||
/* check whether table exists */
|
||||
|
||||
table = [_url gcsTableName];
|
||||
if ([table length] > 0)
|
||||
result = [channel tableExistsWithName:table];
|
||||
|
||||
/* release channel */
|
||||
|
||||
[self releaseChannel:channel]; channel = nil;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* collect old channels */
|
||||
|
||||
- (void)_garbageCollect:(NSTimer *)_timer {
|
||||
NSMutableArray *handlesToRemove;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [self->availableChannels count]) == 0)
|
||||
/* no available channels */
|
||||
return;
|
||||
|
||||
/* collect channels to expire */
|
||||
|
||||
handlesToRemove = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
handle = [self->availableChannels objectAtIndex:i];
|
||||
if (![[handle channel] isOpen]) {
|
||||
[handlesToRemove addObject:handle];
|
||||
continue;
|
||||
}
|
||||
if ([handle age] > ChannelExpireAge) {
|
||||
[handlesToRemove addObject:handle];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove channels */
|
||||
count = [handlesToRemove count];
|
||||
if (debugPools)
|
||||
[self logWithFormat:@"DBPOOL: garbage collecting %d channels.", count];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
handle = [[handlesToRemove objectAtIndex:i] retain];
|
||||
[self->availableChannels removeObject:handle];
|
||||
if ([[handle channel] isOpen])
|
||||
[[handle channel] closeChannel];
|
||||
[handle release];
|
||||
}
|
||||
|
||||
[handlesToRemove release];
|
||||
}
|
||||
|
||||
/* debugging */
|
||||
|
||||
- (BOOL)isDebuggingEnabled {
|
||||
return debugOn;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" #adaptors=%d", [self->urlToAdaptor count]];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSChannelManager */
|
||||
|
||||
@implementation GCSChannelHandle
|
||||
|
||||
- (void)dealloc {
|
||||
[self->channel release];
|
||||
[self->creationTime release];
|
||||
[self->lastReleaseTime release];
|
||||
[self->lastAcquireTime release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (EOAdaptorChannel *)channel {
|
||||
return self->channel;
|
||||
}
|
||||
|
||||
- (BOOL)canHandleURL:(NSURL *)_url {
|
||||
BOOL isSQLite;
|
||||
|
||||
if (_url == nil) {
|
||||
[self logWithFormat:@"MISMATCH: no url .."];
|
||||
return NO;
|
||||
}
|
||||
if (_url == self->url)
|
||||
return YES;
|
||||
|
||||
isSQLite = [[_url scheme] isEqualToString:@"sqlite"];
|
||||
|
||||
if (!isSQLite && ![[self->url host] isEqual:[_url host]]) {
|
||||
[self logWithFormat:@"MISMATCH: different host (%@ vs %@)",
|
||||
[self->url host], [_url host]];
|
||||
return NO;
|
||||
}
|
||||
if (![[self->url gcsDatabaseName] isEqualToString:[_url gcsDatabaseName]]) {
|
||||
[self logWithFormat:@"MISMATCH: different db .."];
|
||||
return NO;
|
||||
}
|
||||
if (!isSQLite) {
|
||||
if (![[self->url user] isEqual:[_url user]]) {
|
||||
[self logWithFormat:@"MISMATCH: different user .."];
|
||||
return NO;
|
||||
}
|
||||
if ([[self->url port] intValue] != [[_url port] intValue]) {
|
||||
[self logWithFormat:@"MISMATCH: different port (%@ vs %@) ..",
|
||||
[self->url port], [_url port]];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)age {
|
||||
return [[NSCalendarDate calendarDate]
|
||||
timeIntervalSinceDate:self->creationTime];
|
||||
}
|
||||
|
||||
/* NSCopying */
|
||||
|
||||
- (id)copyWithZone:(NSZone *)_zone {
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" channel=0x%p", self->channel];
|
||||
if (self->creationTime) [ms appendFormat:@" created=%@", self->creationTime];
|
||||
if (self->lastReleaseTime)
|
||||
[ms appendFormat:@" last-released=%@", self->lastReleaseTime];
|
||||
if (self->lastAcquireTime)
|
||||
[ms appendFormat:@" last-acquired=%@", self->lastAcquireTime];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSChannelHandle */
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSContext_H__
|
||||
#define __GDLContentStore_GCSContext_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSContext
|
||||
|
||||
Context passed to all operations.
|
||||
*/
|
||||
|
||||
@interface GCSContext : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSContext_H__ */
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSContext.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSContext
|
||||
@end /* GCSContext */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFieldExtractor_H__
|
||||
#define __GDLContentStore_GCSFieldExtractor_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSString, NSMutableDictionary;
|
||||
|
||||
@interface GCSFieldExtractor : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFieldExtractor_H__ */
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFieldExtractor.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSFieldExtractor
|
||||
|
||||
- (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end /* GCSFieldExtractor */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFieldInfo_H__
|
||||
#define __GDLContentStore_GCSFieldInfo_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFieldInfo
|
||||
|
||||
The field info inside an .ocs schema file.
|
||||
|
||||
The field info objects are stored in an GCSFolderType.
|
||||
*/
|
||||
|
||||
@class NSString, NSArray;
|
||||
|
||||
@interface GCSFieldInfo : NSObject
|
||||
{
|
||||
NSString *columnName;
|
||||
NSString *sqlType;
|
||||
BOOL allowsNull;
|
||||
BOOL isPrimaryKey;
|
||||
}
|
||||
|
||||
+ (NSArray *)fieldsForPropertyList:(NSArray *)_plist;
|
||||
- (id)initWithPropertyList:(id)_plist;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSString *)columnName;
|
||||
- (NSString *)sqlType;
|
||||
- (BOOL)doesAllowNull;
|
||||
- (BOOL)isPrimaryKey;
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlCreateSection;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFieldInfo_H__ */
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFieldInfo.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSFieldInfo
|
||||
|
||||
+ (NSArray *)fieldsForPropertyList:(NSArray *)_plist {
|
||||
NSMutableArray *fields;
|
||||
unsigned i, count;
|
||||
|
||||
if (_plist == nil)
|
||||
return nil;
|
||||
|
||||
count = [_plist count];
|
||||
fields = [NSMutableArray arrayWithCapacity:count];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSFieldInfo *field;
|
||||
|
||||
field = [[GCSFieldInfo alloc] initWithPropertyList:
|
||||
[_plist objectAtIndex:i]];
|
||||
if (field != nil) [fields addObject:field];
|
||||
[field release];
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
- (id)initWithPropertyList:(id)_plist {
|
||||
if ((self = [super init])) {
|
||||
NSDictionary *plist = _plist;
|
||||
|
||||
self->columnName = [[plist objectForKey:@"columnName"] copy];
|
||||
self->sqlType = [[plist objectForKey:@"sqlType"] copy];
|
||||
|
||||
self->allowsNull = [[plist objectForKey:@"allowsNull"] boolValue];
|
||||
self->isPrimaryKey = [[plist objectForKey:@"isPrimaryKey"] boolValue];
|
||||
|
||||
if (![self->columnName isNotNull] || ![self->sqlType isNotNull]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->columnName release];
|
||||
[self->sqlType release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSString *)columnName {
|
||||
return self->columnName;
|
||||
}
|
||||
- (NSString *)sqlType {
|
||||
return self->sqlType;
|
||||
}
|
||||
|
||||
- (BOOL)doesAllowNull {
|
||||
return self->allowsNull;
|
||||
}
|
||||
- (BOOL)isPrimaryKey {
|
||||
return self->isPrimaryKey;
|
||||
}
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlCreateSection {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:32];
|
||||
[ms appendString:[self columnName]];
|
||||
[ms appendString:@" "];
|
||||
[ms appendString:[self sqlType]];
|
||||
|
||||
[ms appendString:@" "];
|
||||
if (![self doesAllowNull]) [ms appendString:@"NOT "];
|
||||
[ms appendString:@"NULL"];
|
||||
|
||||
if ([self isPrimaryKey]) [ms appendString:@" PRIMARY KEY"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (void)appendAttributesToDescription:(NSMutableString *)ms {
|
||||
id tmp;
|
||||
|
||||
if ((tmp = [self columnName]) != nil) [ms appendFormat:@" column=%@", tmp];
|
||||
if ((tmp = [self sqlType]) != nil) [ms appendFormat:@" sql=%@", tmp];
|
||||
|
||||
if ([self doesAllowNull]) [ms appendString:@" allows-null"];
|
||||
if ([self isPrimaryKey]) [ms appendString:@" pkey"];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
[self appendAttributesToDescription:ms];
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSFieldInfo */
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
Copyright (C) 2007 Helge Hess
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFolder_H__
|
||||
#define __GDLContentStore_GCSFolder_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFolder
|
||||
|
||||
TODO: document
|
||||
|
||||
Fixed Quick-Table SQL fields:
|
||||
- "c_name" (name of the file in the folder)
|
||||
|
||||
Fixed BLOB-Table SQL fields:
|
||||
- "c_name" (name of the file in the folder)
|
||||
- "c_content" (content of the file in the folder)
|
||||
- "c_version" (update revision of the file in the folder)
|
||||
*/
|
||||
|
||||
@class NSString, NSURL, NSNumber, NSArray, NSException, NSMutableString;
|
||||
@class NSDictionary;
|
||||
@class EOQualifier, EOFetchSpecification;
|
||||
@class EOAdaptorChannel;
|
||||
@class GCSFolderManager, GCSFolderType, GCSChannelManager;
|
||||
|
||||
@interface GCSFolder : NSObject
|
||||
{
|
||||
GCSFolderManager *folderManager;
|
||||
GCSFolderType *folderInfo;
|
||||
|
||||
NSNumber *folderId;
|
||||
NSString *folderName;
|
||||
NSString *path;
|
||||
NSURL *location;
|
||||
NSURL *quickLocation;
|
||||
NSURL *aclLocation;
|
||||
NSString *folderTypeName;
|
||||
|
||||
struct {
|
||||
int requiresFolderSelect:1;
|
||||
int sameTableForQuick:1;
|
||||
int reserved:30;
|
||||
} ofFlags;
|
||||
}
|
||||
|
||||
- (id)initWithPath:(NSString *)_path primaryKey:(id)_folderId
|
||||
folderTypeName:(NSString *)_ftname folderType:(GCSFolderType *)_ftype
|
||||
location:(NSURL *)_loc quickLocation:(NSURL *)_qloc
|
||||
aclLocation: (NSURL *)_aloc
|
||||
folderManager:(GCSFolderManager *)_fm;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSNumber *)folderId;
|
||||
- (NSString *)folderName;
|
||||
- (NSString *)path;
|
||||
- (NSURL *)location;
|
||||
- (NSURL *)quickLocation;
|
||||
- (NSURL *)aclLocation;
|
||||
- (NSString *)folderTypeName;
|
||||
|
||||
- (GCSFolderManager *)folderManager;
|
||||
- (GCSChannelManager *)channelManager;
|
||||
|
||||
- (NSString *)storeTableName;
|
||||
- (NSString *)quickTableName;
|
||||
- (NSString *)aclTableName;
|
||||
- (BOOL)isQuickInfoStoredInContentTable;
|
||||
|
||||
/* connection */
|
||||
|
||||
- (EOAdaptorChannel *)acquireStoreChannel;
|
||||
- (EOAdaptorChannel *)acquireQuickChannel;
|
||||
- (EOAdaptorChannel *)acquireAclChannel;
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel;
|
||||
|
||||
- (BOOL)canConnectStore;
|
||||
- (BOOL)canConnectQuick;
|
||||
|
||||
/* operations */
|
||||
|
||||
- (NSArray *)subFolderNames;
|
||||
- (NSArray *)allSubFolderNames;
|
||||
|
||||
- (NSNumber *)versionOfContentWithName:(NSString *)_name;
|
||||
|
||||
- (NSString *)fetchContentWithName:(NSString *)_name;
|
||||
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name
|
||||
baseVersion:(unsigned int)_baseVersion;
|
||||
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name;
|
||||
- (NSException *)deleteContentWithName:(NSString *)_name;
|
||||
|
||||
- (NSException *)deleteFolder;
|
||||
|
||||
- (NSDictionary *)fetchContentsOfAllFiles;
|
||||
|
||||
- (NSArray *)fetchFields:(NSArray *)_flds
|
||||
fetchSpecification:(EOFetchSpecification *)_fs;
|
||||
- (NSArray *)fetchFields:(NSArray *)_flds matchingQualifier:(EOQualifier *)_q;
|
||||
- (NSArray *)fetchAclMatchingQualifier:(EOQualifier *)_q;
|
||||
- (void)deleteAclMatchingQualifier:(EOQualifier *)_q;
|
||||
- (void)deleteAclWithSpecification:(EOFetchSpecification *)_fs;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFolder_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFolderManager_H__
|
||||
#define __GDLContentStore_GCSFolderManager_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFolderManager
|
||||
|
||||
Objects of this class manage the "folder_info" table, they manage the
|
||||
model and manage the tables required for a folder.
|
||||
*/
|
||||
|
||||
@class NSString, NSArray, NSURL, NSDictionary, NSException;
|
||||
@class GCSChannelManager, GCSFolder, GCSFolderType;
|
||||
|
||||
@interface GCSFolderManager : NSObject
|
||||
{
|
||||
GCSChannelManager *channelManager;
|
||||
NSDictionary *nameToType;
|
||||
NSURL *folderInfoLocation;
|
||||
}
|
||||
|
||||
+ (id)defaultFolderManager;
|
||||
- (id)initWithFolderInfoLocation:(NSURL *)_url;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSURL *)folderInfoLocation;
|
||||
- (NSString *)folderInfoTableName;
|
||||
|
||||
/* connection */
|
||||
|
||||
- (GCSChannelManager *)channelManager;
|
||||
- (BOOL)canConnect;
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (NSString *)internalNameFromPath:(NSString *)_path;
|
||||
- (NSArray *)internalNamesFromPath:(NSString *)_path;
|
||||
- (NSString *)pathFromInternalName:(NSString *)_name;
|
||||
|
||||
/* operations */
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path;
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_flag;
|
||||
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path;
|
||||
|
||||
- (NSException *)createFolderOfType:(NSString *)_type withName:(NSString *)_name atPath:(NSString *)_path;
|
||||
- (NSException *)deleteFolderAtPath:(NSString *)_path;
|
||||
|
||||
/* folder types */
|
||||
|
||||
- (GCSFolderType *)folderTypeWithName:(NSString *)_name;
|
||||
|
||||
/* cache management */
|
||||
|
||||
- (void)reset;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFolderManager_H__ */
|
|
@ -0,0 +1,853 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFolderManager.h"
|
||||
#include "GCSChannelManager.h"
|
||||
#include "GCSFolderType.h"
|
||||
#include "GCSFolder.h"
|
||||
#include "NSURL+GCS.h"
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include "common.h"
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
#include <NGExtensions/NGResourceLocator.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
Required database schema:
|
||||
|
||||
<arbitary table>
|
||||
c_path
|
||||
c_path1, path2, path3... [quickPathCount times]
|
||||
c_foldername
|
||||
|
||||
TODO:
|
||||
- add a local cache?
|
||||
*/
|
||||
|
||||
@implementation GCSFolderManager
|
||||
|
||||
static GCSFolderManager *fm = nil;
|
||||
static BOOL debugOn = NO;
|
||||
static BOOL debugSQLGen = NO;
|
||||
static BOOL debugPathTraversal = NO;
|
||||
static int quickPathCount = 4;
|
||||
static NSArray *emptyArray = nil;
|
||||
#if 0
|
||||
static NSString *GCSPathColumnName = @"c_path";
|
||||
static NSString *GCSTypeColumnName = @"c_folder_type";
|
||||
static NSString *GCSTypeRecordName = @"c_folder_type";
|
||||
#endif
|
||||
static NSString *GCSPathRecordName = @"c_path";
|
||||
static NSString *GCSGenericFolderTypeName = @"Container";
|
||||
static const char *GCSPathColumnPattern = "c_path%i";
|
||||
static NSCharacterSet *asciiAlphaNumericCS = nil;
|
||||
|
||||
+ (void)initialize {
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
debugOn = [ud boolForKey:@"GCSFolderManagerDebugEnabled"];
|
||||
debugSQLGen = [ud boolForKey:@"GCSFolderManagerSQLDebugEnabled"];
|
||||
emptyArray = [[NSArray alloc] init];
|
||||
if (!asciiAlphaNumericCS)
|
||||
{
|
||||
asciiAlphaNumericCS
|
||||
= [NSCharacterSet characterSetWithCharactersInString:
|
||||
@"0123456789"
|
||||
@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@"abcdefghijklmnopqrstuvwxyz"];
|
||||
[asciiAlphaNumericCS retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)defaultFolderManager {
|
||||
NSString *s;
|
||||
NSURL *url;
|
||||
if (fm) return fm;
|
||||
|
||||
s = [[NSUserDefaults standardUserDefaults] stringForKey:@"OCSFolderInfoURL"];
|
||||
if ([s length] == 0) {
|
||||
NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not configured.",
|
||||
__PRETTY_FUNCTION__);
|
||||
return nil;
|
||||
}
|
||||
if ((url = [NSURL URLWithString:s]) == nil) {
|
||||
NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not a valid URL: '%@'",
|
||||
__PRETTY_FUNCTION__, s);
|
||||
return nil;
|
||||
}
|
||||
if ((fm = [[self alloc] initWithFolderInfoLocation:url]) == nil) {
|
||||
NSLog(@"ERROR(%s): could not create folder manager with URL: '%@'",
|
||||
__PRETTY_FUNCTION__, [url absoluteString]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSLog(@"Note: setup default manager at: %@", url);
|
||||
return fm;
|
||||
}
|
||||
|
||||
- (NSDictionary *)loadDefaultFolderTypes {
|
||||
NSMutableDictionary *typeMap;
|
||||
NSArray *types;
|
||||
unsigned i, count;
|
||||
|
||||
|
||||
types = [[GCSFolderType resourceLocator] lookupAllFilesWithExtension:@"ocs"
|
||||
doReturnFullPath:NO];
|
||||
if ((count = [types count]) == 0) {
|
||||
[self logWithFormat:@"Note: no GCS folder types found."];
|
||||
return nil;
|
||||
}
|
||||
|
||||
typeMap = [NSMutableDictionary dictionaryWithCapacity:count];
|
||||
|
||||
[self logWithFormat:@"Note: loading %d GCS folder types:", count];
|
||||
for (i = 0, count = [types count]; i < count; i++) {
|
||||
NSString *type;
|
||||
GCSFolderType *typeObject;
|
||||
|
||||
type = [[types objectAtIndex:i] stringByDeletingPathExtension];
|
||||
typeObject = [[GCSFolderType alloc] initWithFolderTypeName:type];
|
||||
|
||||
[self logWithFormat:@" %@: %s",
|
||||
type, [typeObject isNotNull] ? "OK" : "FAIL"];
|
||||
[typeMap setObject:typeObject forKey:type];
|
||||
[typeObject release];
|
||||
}
|
||||
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
- (id)initWithFolderInfoLocation:(NSURL *)_url {
|
||||
if (_url == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): missing folder info url!",
|
||||
__PRETTY_FUNCTION__];
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init])) {
|
||||
self->channelManager = [[GCSChannelManager defaultChannelManager] retain];
|
||||
self->folderInfoLocation = [_url retain];
|
||||
|
||||
if ([[self folderInfoTableName] length] == 0) {
|
||||
[self logWithFormat:@"ERROR(%s): missing tablename in URL: %@",
|
||||
__PRETTY_FUNCTION__, [_url absoluteString]];
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* register default folder types */
|
||||
self->nameToType = [[self loadDefaultFolderTypes] copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->nameToType release];
|
||||
[self->folderInfoLocation release];
|
||||
[self->channelManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSURL *)folderInfoLocation {
|
||||
return self->folderInfoLocation;
|
||||
}
|
||||
|
||||
- (NSString *)folderInfoTableName {
|
||||
return [[self folderInfoLocation] gcsTableName];
|
||||
}
|
||||
|
||||
/* connection */
|
||||
|
||||
- (GCSChannelManager *)channelManager {
|
||||
return self->channelManager;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannel {
|
||||
EOAdaptorChannel *ch;
|
||||
|
||||
ch = [[self channelManager] acquireOpenChannelForURL:
|
||||
[self folderInfoLocation]];
|
||||
return ch;
|
||||
}
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
|
||||
[[self channelManager] releaseChannel:_channel];
|
||||
if (debugOn) [self debugWithFormat:@"released channel: %@", _channel];
|
||||
}
|
||||
|
||||
- (BOOL)canConnect {
|
||||
return [[self channelManager] canConnect:[self folderInfoLocation]];
|
||||
}
|
||||
|
||||
- (NSArray *)performSQL:(NSString *)_sql {
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
NSMutableArray *rows;
|
||||
NSDictionary *row;
|
||||
NSArray *attrs;
|
||||
|
||||
/* acquire channel */
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel!"];
|
||||
return nil;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
|
||||
/* run SQL */
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:_sql]) != nil) {
|
||||
[self logWithFormat:@"ERROR(%s): cannot execute\n SQL '%@':\n %@",
|
||||
__PRETTY_FUNCTION__, _sql, ex];
|
||||
[self releaseChannel:channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* fetch results */
|
||||
|
||||
attrs = [channel describeResults:NO /* do not beautify names */];
|
||||
rows = [NSMutableArray arrayWithCapacity:16];
|
||||
while ((row = [channel fetchAttributes:attrs withZone:NULL]) != nil)
|
||||
[rows addObject:row];
|
||||
|
||||
[self releaseChannel:channel];
|
||||
return rows;
|
||||
}
|
||||
|
||||
/* row factory */
|
||||
|
||||
- (GCSFolder *)folderForRecord:(NSDictionary *)_record {
|
||||
GCSFolder *folder;
|
||||
GCSFolderType *folderType;
|
||||
NSString *folderTypeName, *locationString, *folderName, *path;
|
||||
NSNumber *folderId;
|
||||
NSURL *location, *quickLocation, *aclLocation;
|
||||
|
||||
if (_record == nil) return nil;
|
||||
|
||||
folderTypeName = [_record objectForKey:@"c_folder_type"];
|
||||
if (![folderTypeName isNotNull]) {
|
||||
[self logWithFormat:@"ERROR(%s): missing type in folder: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
return nil;
|
||||
}
|
||||
if ((folderType = [self folderTypeWithName:folderTypeName]) == nil) {
|
||||
[self logWithFormat:
|
||||
@"ERROR(%s): could not resolve type '%@' of folder: %@",
|
||||
__PRETTY_FUNCTION__,
|
||||
folderTypeName, [_record valueForKey:@"c_path"]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
folderId = [_record objectForKey:@"c_folder_id"];
|
||||
folderName = [_record objectForKey:@"c_path"];
|
||||
path = [self pathFromInternalName:folderName];
|
||||
|
||||
locationString = [_record objectForKey:@"c_location"];
|
||||
location = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
if (location == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): missing folder location in record: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
return nil;
|
||||
}
|
||||
|
||||
locationString = [_record objectForKey:@"c_quick_location"];
|
||||
quickLocation = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
|
||||
if (quickLocation == nil) {
|
||||
[self logWithFormat:@"WARNING(%s): missing quick location in record: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
}
|
||||
|
||||
locationString = [_record objectForKey:@"c_acl_location"];
|
||||
aclLocation = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
|
||||
folder = [[GCSFolder alloc] initWithPath:path primaryKey:folderId
|
||||
folderTypeName:folderTypeName
|
||||
folderType:folderType
|
||||
location:location quickLocation:quickLocation
|
||||
aclLocation:aclLocation
|
||||
folderManager:self];
|
||||
return [folder autorelease];
|
||||
}
|
||||
|
||||
/* path SQL */
|
||||
|
||||
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* generates a WHERE qualifier for matching the "quick" entries */
|
||||
NSMutableString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [_names count]) == 0) {
|
||||
[self debugWithFormat:@"WARNING(%s): passed in empty name array!",
|
||||
__PRETTY_FUNCTION__];
|
||||
return @"1 = 2";
|
||||
}
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:(count * 8)];
|
||||
for (i = 0; i < quickPathCount; i++) {
|
||||
NSString *pathColumn;
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, GCSPathColumnPattern, (i + 1));
|
||||
pathColumn = [[NSString alloc] initWithCString:buf];
|
||||
|
||||
/* Note: the AND addition must be inside the if's for non-exact stuff */
|
||||
|
||||
if (i < count) {
|
||||
/* exact match, regular column */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendFormat:@" = '%@'", [_names objectAtIndex:i]];
|
||||
}
|
||||
else if (_beExact) {
|
||||
/* exact match, ensure that all additional quick-cols are NULL */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendString:@" IS NULL"];
|
||||
if (debugPathTraversal) [self logWithFormat:@"BE EXACT, NULL columns"];
|
||||
}
|
||||
else if (_directSubs) {
|
||||
/* fetch immediate subfolders */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
if (i == count) {
|
||||
/* if it is a direct subfolder, the next path cannot be empty */
|
||||
[sql appendString:@" IS NOT NULL"];
|
||||
if (debugPathTraversal)
|
||||
[self logWithFormat:@"DIRECT SUBS, first level"];
|
||||
}
|
||||
else {
|
||||
/* but for 'direct' subfolders, all following things must be empty */
|
||||
[sql appendString:@" IS NULL"];
|
||||
if (debugPathTraversal)
|
||||
[self logWithFormat:@"DIRECT SUBS, lower level"];
|
||||
}
|
||||
}
|
||||
|
||||
[pathColumn release];
|
||||
}
|
||||
|
||||
if (_beExact && (count > quickPathCount)) {
|
||||
[sql appendString:@" AND c_foldername = '"];
|
||||
[sql appendString:[_names lastObject]];
|
||||
[sql appendString:@"'"];
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString *)generateSQLPathFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT c_path FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
if (debugSQLGen) [self logWithFormat:@"PathFetch-SQL: %@", sql];
|
||||
return sql;
|
||||
}
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (BOOL)_isStandardizedPath:(NSString *)_path {
|
||||
if (![_path isAbsolutePath]) return NO;
|
||||
if ([_path rangeOfString:@".."].length > 0) return NO;
|
||||
if ([_path rangeOfString:@"~"].length > 0) return NO;
|
||||
if ([_path rangeOfString:@"//"].length > 0) return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)internalNameFromPath:(NSString *)_path {
|
||||
// TODO: ensure proper path and SQL escaping!
|
||||
|
||||
if (![self _isStandardizedPath:_path]) {
|
||||
[self debugWithFormat:@"%s: not a standardized path: '%@'",
|
||||
__PRETTY_FUNCTION__, _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([_path hasSuffix:@"/"] && [_path length] > 1)
|
||||
_path = [_path substringToIndex:([_path length] - 1)];
|
||||
|
||||
return _path;
|
||||
}
|
||||
- (NSArray *)internalNamesFromPath:(NSString *)_path {
|
||||
NSString *fname;
|
||||
NSArray *fnames;
|
||||
|
||||
if ((fname = [self internalNameFromPath:_path]) == nil)
|
||||
return nil;
|
||||
|
||||
if ([fname hasPrefix:@"/"])
|
||||
fname = [fname substringFromIndex:1];
|
||||
|
||||
fnames = [fname componentsSeparatedByString:@"/"];
|
||||
if ([fnames count] == 0)
|
||||
return nil;
|
||||
|
||||
return fnames;
|
||||
}
|
||||
- (NSString *)pathFromInternalName:(NSString *)_name {
|
||||
/* for incomplete pathes, like '/Users/helge/' */
|
||||
return _name;
|
||||
}
|
||||
- (NSString *)pathPartFromInternalName:(NSString *)_name {
|
||||
/* for incomplete pathes, like 'Users/' */
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (NSDictionary *)filterRecords:(NSArray *)_records forPath:(NSString *)_path {
|
||||
unsigned i, count;
|
||||
NSString *name;
|
||||
|
||||
if (_records == nil) return nil;
|
||||
if ((name = [self internalNameFromPath:_path]) == nil) return nil;
|
||||
|
||||
for (i = 0, count = [_records count]; i < count; i++) {
|
||||
NSDictionary *record;
|
||||
NSString *recName;
|
||||
|
||||
record = [_records objectAtIndex:i];
|
||||
recName = [record objectForKey:GCSPathRecordName];
|
||||
#if 0
|
||||
[self logWithFormat:@"check '%@' vs '%@' (%@)...",
|
||||
name, recName, [_records objectAtIndex:i]];
|
||||
#endif
|
||||
|
||||
if ([name isEqualToString:recName])
|
||||
return [_records objectAtIndex:i];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path {
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return NO;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return NO;
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
if (count == 1) {
|
||||
NSDictionary *record;
|
||||
NSString *sname;
|
||||
|
||||
record = [records objectAtIndex:0];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
return [fname isEqualToString:sname];
|
||||
}
|
||||
|
||||
[self logWithFormat:@"records: %@", records];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_recursive{
|
||||
NSMutableArray *result;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return emptyArray;
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
fname = [fname stringByAppendingString:@"/"]; /* add slash */
|
||||
for (i = 0; i < count; i++) {
|
||||
NSDictionary *record;
|
||||
NSString *sname, *spath;
|
||||
|
||||
record = [records objectAtIndex:i];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
if (![sname hasPrefix:fname]) /* does not match at all ... */
|
||||
continue;
|
||||
|
||||
/* strip prefix and following slash */
|
||||
sname = [sname substringFromIndex:[fname length]];
|
||||
spath = [self pathPartFromInternalName:sname];
|
||||
|
||||
if (_recursive) {
|
||||
if ([spath length] > 0) [result addObject:spath];
|
||||
}
|
||||
else {
|
||||
/* direct children only, so exclude everything with a slash */
|
||||
if ([sname rangeOfString:@"/"].length == 0 && [spath length] > 0)
|
||||
[result addObject:spath];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path {
|
||||
NSMutableString *sql;
|
||||
NSArray *fnames, *records;
|
||||
NSString *ws;
|
||||
NSDictionary *record;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* generate SQL to fetch folder attributes */
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT "];
|
||||
[sql appendString:@"c_folder_id, "];
|
||||
[sql appendString:@"c_path, "];
|
||||
[sql appendString:@"c_location, c_quick_location, c_acl_location,"];
|
||||
[sql appendString:@" c_folder_type"];
|
||||
[sql appendString:@" FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
|
||||
if (debugSQLGen) [self logWithFormat:@"folderAtPath: %@", sql];
|
||||
|
||||
/* fetching */
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// TODO: need to filter on path
|
||||
// required when we start to have deeper hierarchies
|
||||
// => isn't that already done below?
|
||||
|
||||
if ([records count] != 1) {
|
||||
if ([records count] == 0) {
|
||||
[self debugWithFormat:@"found no records for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self logWithFormat:@"ERROR(%s): more than one row for path: '%@'",
|
||||
__PRETTY_FUNCTION__, _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((record = [self filterRecords:records forPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"found no record for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self folderForRecord:record];
|
||||
}
|
||||
|
||||
- (NSString *)baseTableNameWithUID:(NSString *)_uid {
|
||||
NSDate *now;
|
||||
unichar currentChar;
|
||||
unsigned int count, max, done;
|
||||
NSMutableString *newUID;
|
||||
|
||||
newUID = [NSMutableString string];
|
||||
now = [NSDate date];
|
||||
|
||||
max = [_uid length];
|
||||
done = 0;
|
||||
count = 0;
|
||||
while (done < 8 && count < max)
|
||||
{
|
||||
currentChar = [_uid characterAtIndex: count];
|
||||
if ([asciiAlphaNumericCS characterIsMember: currentChar])
|
||||
{
|
||||
[newUID appendFormat: @"%c", currentChar];
|
||||
done++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat: @"%@%u",
|
||||
newUID, [now timeIntervalSince1970]];
|
||||
}
|
||||
|
||||
- (NSException *)createFolderOfType:(NSString *)_type
|
||||
withName:(NSString*)_name atPath:(NSString *)_path
|
||||
{
|
||||
// TBD: badly broken, needs to be wrapped in a transaction.
|
||||
// TBD: would be best to perform all operations as a single SQL statement.
|
||||
GCSFolderType *ftype;
|
||||
NSString *tableName, *quickTableName, *aclTableName;
|
||||
NSString *baseURL, *pathElement;
|
||||
EOAdaptorChannel <GCSEOAdaptorChannel> *channel;
|
||||
NSEnumerator *pathElements;
|
||||
NSMutableArray *paths;
|
||||
NSException *error;
|
||||
NSString *sql;
|
||||
|
||||
paths = [[NSMutableArray alloc] initWithCapacity: 5];
|
||||
|
||||
pathElements = [[_path componentsSeparatedByString: @"/"] objectEnumerator];
|
||||
while ((pathElement = [pathElements nextObject]) != nil) {
|
||||
NSString *p = [[NSString alloc] initWithFormat: @"'%@'", pathElement];
|
||||
[paths addObject: p];
|
||||
[p release]; p = nil;
|
||||
}
|
||||
while ([paths count] < 5)
|
||||
[paths addObject: @"NULL"];
|
||||
|
||||
// TBD: fix SQL injection issue!
|
||||
sql = [NSString stringWithFormat: @"SELECT * FROM %@ WHERE c_path = '%@'",
|
||||
[self folderInfoTableName], _path];
|
||||
if ([[self performSQL: sql] isNotEmpty]) {
|
||||
return [NSException exceptionWithName:@"GCSExitingFolder"
|
||||
reason:@"a folder already exists at that path"
|
||||
userInfo:nil];
|
||||
}
|
||||
if ((ftype = [self folderTypeWithName:_type]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolderType"
|
||||
reason:@"missing folder type"userInfo:nil];
|
||||
}
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not open channel"
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
tableName = [self baseTableNameWithUID: [paths objectAtIndex: 2]];
|
||||
quickTableName = [tableName stringByAppendingString: @"_quick"];
|
||||
aclTableName = [tableName stringByAppendingString: @"_acl"];
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:aclTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
if ((error = [channel createGCSFolderTableWithName: tableName]) != nil)
|
||||
return error;
|
||||
|
||||
sql = [ftype sqlQuickCreateWithTableName: quickTableName];
|
||||
if (debugSQLGen) [self logWithFormat:@"quick-Create: %@", sql];
|
||||
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
/* 'rollback' TBD: wrap in proper tx */
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
if (debugSQLGen) [self logWithFormat:@"acl-Create: %@", sql];
|
||||
if ((error = [channel createGCSFolderACLTableWithName: aclTableName])
|
||||
!= nil) {
|
||||
/* 'rollback' TBD: wrap in proper tx */
|
||||
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// TBD: fix SQL injection issues
|
||||
baseURL
|
||||
= [[folderInfoLocation absoluteString] stringByDeletingLastPathComponent];
|
||||
|
||||
sql = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
|
||||
@" c_foldername, c_location, c_quick_location,"
|
||||
@" c_acl_location, c_folder_type)"
|
||||
@" VALUES ('%@', %@, %@, %@, %@, '%@', '%@/%@',"
|
||||
@" '%@/%@', '%@/%@', '%@')",
|
||||
[self folderInfoTableName], _path,
|
||||
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
|
||||
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
|
||||
_name,
|
||||
baseURL, tableName,
|
||||
baseURL, quickTableName,
|
||||
baseURL, aclTableName,
|
||||
_type];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
return error;
|
||||
|
||||
[paths release]; paths = nil;
|
||||
[self releaseChannel: channel];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSException *)deleteFolderAtPath:(NSString *)_path {
|
||||
GCSFolder *folder;
|
||||
NSArray *fnames;
|
||||
NSString *sql, *ws;
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
|
||||
if ((folder = [self folderAtPath:_path]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolder"
|
||||
reason:@"missing folder"
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
|
||||
sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@",
|
||||
[self folderInfoTableName], ws];
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self releaseChannel:channel];
|
||||
return ex;
|
||||
}
|
||||
|
||||
[self releaseChannel:channel];
|
||||
|
||||
return [folder deleteFolder];
|
||||
}
|
||||
|
||||
/* folder types */
|
||||
|
||||
- (GCSFolderType *)folderTypeWithName:(NSString *)_name {
|
||||
NSString *specificName;
|
||||
GCSFolderType *type;
|
||||
|
||||
if ([_name length] == 0)
|
||||
_name = GCSGenericFolderTypeName;
|
||||
|
||||
specificName = [NSString stringWithFormat: @"%@-%@",
|
||||
_name, [folderInfoLocation scheme]];
|
||||
type = [self->nameToType objectForKey: [specificName lowercaseString]];
|
||||
if (!type)
|
||||
type = [self->nameToType objectForKey:[_name lowercaseString]];
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* cache management */
|
||||
|
||||
- (void)reset {
|
||||
/* does nothing in the moment, but we need a way to signal refreshes */
|
||||
}
|
||||
|
||||
/* debugging */
|
||||
|
||||
- (BOOL)isDebuggingEnabled {
|
||||
return debugOn;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" url=%@", [self->folderInfoLocation absoluteString]];
|
||||
[ms appendFormat:@" channel-manager=0x%p", [self channelManager]];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSFolderManager */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFolderType_H__
|
||||
#define __GDLContentStore_GCSFolderType_H__
|
||||
|
||||
/*
|
||||
GCSFolderType
|
||||
|
||||
This is the "model" of a folder, it specifies what quick attributes are
|
||||
available, in which tables it is stored and how it is retrieved.
|
||||
|
||||
For now, we only support one 'quick' table (we might want to have multiple
|
||||
ones in the future).
|
||||
|
||||
Note: using the 'folderQualifier' we are actually prepared for 'multiple
|
||||
folders in a single table' setups. So in case we want to go that
|
||||
route later, we can still do it :-)
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSString, NSArray, NSDictionary;
|
||||
@class EOQualifier;
|
||||
@class NGResourceLocator;
|
||||
@class GCSFolder, GCSFieldExtractor;
|
||||
|
||||
@interface GCSFolderType : NSObject
|
||||
{
|
||||
NSString *blobTablePattern; // eg 'SOGo_$folderId$_blob
|
||||
NSString *quickTablePattern; // eg 'SOGo_$folderId$_quick
|
||||
NSArray *fields; // GCSFieldInfo objects
|
||||
NSDictionary *fieldDict; // maps a name to GCSFieldInfo
|
||||
EOQualifier *folderQualifier; // to further limit the table set
|
||||
NSString *extractorClassName;
|
||||
GCSFieldExtractor *extractor;
|
||||
}
|
||||
|
||||
+ (id)folderTypeWithName:(NSString *)_type;
|
||||
|
||||
- (id)initWithPropertyList:(id)_plist;
|
||||
- (id)initWithContentsOfFile:(NSString *)_path;
|
||||
- (id)initWithFolderTypeName:(NSString *)_typeName;
|
||||
|
||||
/* operations */
|
||||
|
||||
- (NSString *)blobTableNameForFolder:(GCSFolder *)_folder;
|
||||
- (NSString *)quickTableNameForFolder:(GCSFolder *)_folder;
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlQuickCreateWithTableName:(NSString *)_tabName;
|
||||
|
||||
/* quick support */
|
||||
|
||||
- (GCSFieldExtractor *)quickExtractor;
|
||||
|
||||
/* locator used to find .ocs files */
|
||||
|
||||
+ (NGResourceLocator *)resourceLocator;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFolderType_H__ */
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFolderType.h"
|
||||
#include "GCSFolder.h"
|
||||
#include "GCSFieldInfo.h"
|
||||
#include "GCSFieldExtractor.h"
|
||||
#include "common.h"
|
||||
#include <EOControl/EOKeyValueCoding.h>
|
||||
#include <NGExtensions/NGResourceLocator.h>
|
||||
|
||||
@implementation GCSFolderType
|
||||
|
||||
- (id)initWithPropertyList:(id)_plist {
|
||||
if ((self = [super init])) {
|
||||
NSDictionary *plist = _plist;
|
||||
|
||||
self->blobTablePattern = [[plist objectForKey:@"blobTablePattern"] copy];
|
||||
self->quickTablePattern = [[plist objectForKey:@"quickTablePattern"]copy];
|
||||
|
||||
self->extractorClassName =
|
||||
[[plist objectForKey:@"extractorClassName"] copy];
|
||||
// TODO: qualifier;
|
||||
|
||||
self->fields = [[GCSFieldInfo fieldsForPropertyList:
|
||||
[plist objectForKey:@"fields"]] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfFile:(NSString *)_path {
|
||||
NSDictionary *plist;
|
||||
|
||||
plist = [NSDictionary dictionaryWithContentsOfFile:_path];
|
||||
if (plist == nil) {
|
||||
NSLog(@"ERROR(%s): could not read dictionary at path %@",
|
||||
__PRETTY_FUNCTION__, _path);
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
return [self initWithPropertyList:plist];
|
||||
}
|
||||
|
||||
+ (NGResourceLocator *)resourceLocator {
|
||||
NGResourceLocator *loc;
|
||||
|
||||
// TODO: fix me, GCS instead of OCS
|
||||
loc = [NGResourceLocator resourceLocatorForGNUstepPath:
|
||||
@"Library/OCSTypeModels"
|
||||
fhsPath:@"share/ocs"];
|
||||
return loc;
|
||||
}
|
||||
|
||||
+ (id)folderTypeWithName:(NSString *)_typeName {
|
||||
NSString *filename, *path;
|
||||
|
||||
// TODO: fix me, GCS instead of OCS
|
||||
filename = [_typeName stringByAppendingPathExtension:@"ocs"];
|
||||
path = [[self resourceLocator] lookupFileWithName:filename];
|
||||
|
||||
if (path != nil)
|
||||
return [[self alloc] initWithContentsOfFile:path];
|
||||
|
||||
NSLog(@"ERROR(%s): did not find model for type: '%@'",
|
||||
__PRETTY_FUNCTION__, _typeName);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initWithFolderTypeName:(NSString *)_typeName {
|
||||
// DEPRECATED
|
||||
[self release];
|
||||
return [[GCSFolderType folderTypeWithName:_typeName] retain];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->extractor release];
|
||||
[self->extractorClassName release];
|
||||
[self->blobTablePattern release];
|
||||
[self->quickTablePattern release];
|
||||
[self->fields release];
|
||||
[self->fieldDict release];
|
||||
[self->folderQualifier release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operations */
|
||||
|
||||
- (NSString *)blobTableNameForFolder:(GCSFolder *)_folder {
|
||||
return [self->blobTablePattern
|
||||
stringByReplacingVariablesWithBindings:_folder];
|
||||
}
|
||||
- (NSString *)quickTableNameForFolder:(GCSFolder *)_folder {
|
||||
return [self->quickTablePattern
|
||||
stringByReplacingVariablesWithBindings:_folder];
|
||||
}
|
||||
|
||||
- (EOQualifier *)qualifierForFolder:(GCSFolder *)_folder {
|
||||
NSArray *keys;
|
||||
NSDictionary *bindings;
|
||||
|
||||
keys = [[self->folderQualifier allQualifierKeys] allObjects];
|
||||
if ([keys count] == 0)
|
||||
return self->folderQualifier;
|
||||
|
||||
bindings = [_folder valuesForKeys:keys];
|
||||
return [self->folderQualifier qualifierWithBindings:bindings
|
||||
requiresAllVariables:NO];
|
||||
}
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlQuickCreateWithTableName:(NSString *)_tabName {
|
||||
NSMutableString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:512];
|
||||
[sql appendString:@"CREATE TABLE "];
|
||||
[sql appendString:_tabName];
|
||||
[sql appendString:@" (\n"];
|
||||
|
||||
count = [self->fields count];
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i > 0) [sql appendString:@",\n"];
|
||||
|
||||
[sql appendString:@" "];
|
||||
[sql appendString:[[self->fields objectAtIndex:i] sqlCreateSection]];
|
||||
}
|
||||
|
||||
[sql appendString:@"\n)"];
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/* quick support */
|
||||
|
||||
- (GCSFieldExtractor *)quickExtractor {
|
||||
Class clazz;
|
||||
|
||||
if (self->extractor != nil) {
|
||||
return [self->extractor isNotNull]
|
||||
? self->extractor : (GCSFieldExtractor *)nil;
|
||||
}
|
||||
|
||||
clazz = self->extractorClassName
|
||||
? NSClassFromString(self->extractorClassName)
|
||||
: [GCSFieldExtractor class];
|
||||
if (clazz == Nil) {
|
||||
[self logWithFormat:@"ERROR: did not find field extractor class!"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((self->extractor = [[clazz alloc] init]) == nil) {
|
||||
[self logWithFormat:@"ERROR: could not create field extractor of class %@",
|
||||
clazz];
|
||||
return nil;
|
||||
}
|
||||
return self->extractor;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" blobtable='%@'", self->blobTablePattern];
|
||||
[ms appendFormat:@" quicktable='%@'", self->quickTablePattern];
|
||||
[ms appendFormat:@" fields=%@", self->fields];
|
||||
[ms appendFormat:@" extractor=%@", self->extractorClassName];
|
||||
|
||||
if (self->folderQualifier)
|
||||
[ms appendFormat:@" qualifier=%@", self->folderQualifier];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSFolderType */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSStringFormatter_H__
|
||||
#define __GDLContentStore_GCSStringFormatter_H__
|
||||
|
||||
#include <NGExtensions/NSString+Escaping.h>
|
||||
|
||||
@interface GCSStringFormatter : NSObject < NGStringEscaping >
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)sharedFormatter;
|
||||
|
||||
- (NSString *)stringByFormattingString:(NSString *)_s;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSStringFormatter_H__ */
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSStringFormatter.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSStringFormatter
|
||||
|
||||
static NSCharacterSet *escapeSet = nil;
|
||||
|
||||
+ (void)initialize {
|
||||
static BOOL didInit = NO;
|
||||
|
||||
if(didInit)
|
||||
return;
|
||||
|
||||
didInit = YES;
|
||||
escapeSet =
|
||||
[[NSCharacterSet characterSetWithCharactersInString:@"\\'"] retain];
|
||||
}
|
||||
|
||||
+ (id)sharedFormatter {
|
||||
static id sharedInstance = nil;
|
||||
if(!sharedInstance) {
|
||||
sharedInstance = [[self alloc] init];
|
||||
}
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (NSString *)stringByFormattingString:(NSString *)_s {
|
||||
NSString *s;
|
||||
|
||||
s = [_s stringByEscapingCharactersFromSet:escapeSet
|
||||
usingStringEscaping:self];
|
||||
return [NSString stringWithFormat:@"'%@'", s];
|
||||
}
|
||||
|
||||
- (NSString *)stringByEscapingString:(NSString *)_s {
|
||||
if([_s isEqualToString:@"\\"]) {
|
||||
return @"\\\\"; /* easy ;-) */
|
||||
}
|
||||
return @"\\'";
|
||||
}
|
||||
|
||||
@end /* GCSStringFormatter */
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_NSURL_GCS_H__
|
||||
#define __GDLContentStore_NSURL_GCS_H__
|
||||
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
/*
|
||||
"Database URLs"
|
||||
|
||||
We use the schema:
|
||||
postgresql://[user]:[password]@[host]:[port]/[dbname]/[tablename]
|
||||
*/
|
||||
|
||||
@interface NSURL(GCS)
|
||||
|
||||
- (NSString *)gcsDatabaseName;
|
||||
- (NSString *)gcsTableName;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_NSURL_GCS_H__ */
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "NSURL+GCS.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation NSURL(GCS)
|
||||
|
||||
- (NSString *)gcsPathComponent:(unsigned)_idx {
|
||||
NSString *p;
|
||||
NSArray *pcs;
|
||||
unsigned len;
|
||||
|
||||
p = [self path];
|
||||
if ([p length] == 0)
|
||||
return nil;
|
||||
|
||||
pcs = [p componentsSeparatedByString:@"/"];
|
||||
if ((len = [pcs count]) == 0)
|
||||
return nil;
|
||||
if (len <= _idx)
|
||||
return nil;
|
||||
return [pcs objectAtIndex:_idx];
|
||||
}
|
||||
|
||||
- (NSString *)gcsDatabaseName {
|
||||
return [self gcsPathComponent:1];
|
||||
}
|
||||
- (NSString *)gcsTableName {
|
||||
return [[self path] lastPathComponent];
|
||||
}
|
||||
|
||||
@end /* NSURL(GCS) */
|
|
@ -0,0 +1,117 @@
|
|||
Storage Backend
|
||||
===============
|
||||
|
||||
The storage backend implements the "low level" folder abstraction, which is
|
||||
basically an arbitary "BLOB" containing some document. The feature is that
|
||||
we extract "quick access" / "searchable" attributes from the document content.
|
||||
|
||||
Further it contains the "folder management" API, as named folders can be stored
|
||||
in different databases.
|
||||
Note: we need a way to tell where "new" folders should be created
|
||||
Note: to sync with LDAP we need to periodically delete or archive old folders
|
||||
|
||||
Folders have associated a type (like 'calendar') which defines the query
|
||||
attributes and serialization format.
|
||||
|
||||
TODO
|
||||
====
|
||||
- fix some OCS naming
|
||||
- defaults
|
||||
- lookup directories
|
||||
- hierarchies deeper than 4 (properly filter on path in OCS)
|
||||
|
||||
Open Questions
|
||||
==============
|
||||
|
||||
System-meta-data in the blob-table or in the quick-table?
|
||||
- master data belongs into the blob table
|
||||
- could be regular 'NSxxx' keys to differentiate meta data from
|
||||
|
||||
Class Hierarchy
|
||||
===============
|
||||
|
||||
[NSObject]
|
||||
OCSContext - tracking context
|
||||
OCSFolder - represents a single folder
|
||||
OCSFolderManager - manages folders
|
||||
OCSFolderType - the mapping info for a specific folder-type
|
||||
OCSFieldInfo - mapping info for one 'quick field'
|
||||
OCSChannelManager - maintains EOAdaptorChannel objects
|
||||
|
||||
TBD:
|
||||
- field 'extractor'
|
||||
- field 'value' (eg array values for participants?)
|
||||
- BLOB archiver/unarchiver
|
||||
|
||||
Defaults
|
||||
========
|
||||
|
||||
OCSFolderInfoURL - the DB URL where the folder-info table is located
|
||||
eg: http://OGo:OGo@localhost/test/folder_info
|
||||
|
||||
OCSFolderManagerDebugEnabled - enable folder-manager debug logs
|
||||
OCSFolderManagerSQLDebugEnabled - enable folder-manager SQL gen debug logs
|
||||
|
||||
OCSChannelManagerDebugEnabled - enable channel debug pooling logs
|
||||
OCSChannelManagerPoolDebugEnabled - debug pool handle allocation
|
||||
|
||||
OCSChannelExpireAge - if that age in seconds is exceeded, a channel
|
||||
will be removed from the pool
|
||||
OCSChannelCollectionTimer - time in seconds. each n-seconds the pool will be
|
||||
checked for channels too old
|
||||
|
||||
[PGDebugEnabled] - enable PostgreSQL adaptor debugging
|
||||
|
||||
URLs
|
||||
====
|
||||
|
||||
"Database URLs"
|
||||
|
||||
We use the schema:
|
||||
postgresql://[user]:[password]@[host]:[port]/[dbname]/[tablename]
|
||||
|
||||
Support Tools
|
||||
=============
|
||||
|
||||
- tools we need:
|
||||
- one to recreate a quick table based on the blob table
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
- need to use http:// URLs for connect info, until generic URLs in
|
||||
libFoundation are fixed (the parses breaks on the login/password parts)
|
||||
|
||||
QA
|
||||
==
|
||||
|
||||
Q: Why do we use two tables, we could store the quick columns in the blob?
|
||||
==
|
||||
They could be in the same table. We considered using separate tables since the
|
||||
quick table is likely to be recreated now and then if BLOB indexing
|
||||
requirements change.
|
||||
Actually one could even use different _quick tables which share a common BLOB
|
||||
table.
|
||||
(a quick table is nothing more than a database index and like with DB indexes
|
||||
multiple ones for different requirements can make sense).
|
||||
|
||||
Further it might improve caching behaviour for row based caches (the quick
|
||||
table is going to be queried much more often) - not sure whether this is
|
||||
relevant with PostgreSQL, probably not?
|
||||
|
||||
Q: Can we use a VARCHAR primary key?
|
||||
==
|
||||
We asked in the postgres IRC channel and apparently the performance penalty of
|
||||
string primary keys isn't big.
|
||||
We could also use an 'internal' int sequence in addition (might be useful for
|
||||
supporting ZideLook)
|
||||
Motivation: the 'iCalendar' ID is a string and usually looks like a GUID.
|
||||
|
||||
Q: Why using VARCHAR instead of TEXT in the BLOB?
|
||||
==
|
||||
To quote PostgreSQL documentation:
|
||||
"There are no performance differences between these three types, apart from
|
||||
the increased storage size when using the blank-padded type."
|
||||
So varchar(xx) is just a large TEXT. Since we intend to store mostly small
|
||||
snippets of data (tiny XML fragments), we considered VARCHAR the more
|
||||
appropriate type.
|
|
@ -0,0 +1,14 @@
|
|||
# Version file
|
||||
|
||||
MAJOR_VERSION:=4
|
||||
MINOR_VERSION:=7
|
||||
SUBMINOR_VERSION:=49
|
||||
|
||||
# v4.5.29 requires libNGExtensions v4.5.161
|
||||
# v4.5.26 does not require libNGiCal anymore
|
||||
# v0.9.19 requires libNGiCal v4.5.40
|
||||
# v0.9.18 requires libNGiCal v4.5.38
|
||||
# v0.9.17 requires libNGiCal v4.5.37
|
||||
# v0.9.11 requires libFoundation v1.0.63
|
||||
# v0.9.11 requires libNGExtensions v4.3.125
|
||||
# v0.9.7 requires libGDLAccess v1.1.35
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright (C) 2004 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
// $Id: common.h 673 2005-03-20 19:09:53Z helge $
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#include <NGExtensions/NGExtensions.h>
|
||||
|
||||
#if NeXT_RUNTIME || APPLE_RUNTIME
|
||||
# define objc_free(__mem__) free(__mem__)
|
||||
# define objc_malloc(__size__) malloc(__size__)
|
||||
# define objc_calloc(__cnt__, __size__) calloc(__cnt__, __size__)
|
||||
# define objc_realloc(__ptr__, __size__) realloc(__ptr__, __size__)
|
||||
# ifndef sel_eq
|
||||
# define sel_eq(sela,selb) (sela==selb?YES:NO)
|
||||
# endif
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
# postprocessing
|
||||
|
||||
# FHS support (this is a hack and is going to be done by gstep-make!)
|
||||
|
||||
# NOTE: you need to define FHS_HEADER_FILES_INSTALL_DIR for one library
|
||||
|
||||
ifneq ($(FHS_INSTALL_ROOT),)
|
||||
|
||||
FHS_INCLUDE_DIR=$(FHS_INSTALL_ROOT)/include/
|
||||
FHS_BIN_DIR=$(FHS_INSTALL_ROOT)/bin
|
||||
FHS_LIB_DIR=$(CONFIGURE_FHS_INSTALL_LIBDIR)
|
||||
|
||||
NONFHS_LIBDIR="$(GNUSTEP_LIBRARIES)/$(GNUSTEP_TARGET_LDIR)/"
|
||||
NONFHS_LIBNAME="$(LIBRARY_NAME)$(LIBRARY_NAME_SUFFIX)$(SHARED_LIBEXT)"
|
||||
NONFHS_BINDIR="$(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)"
|
||||
|
||||
|
||||
fhs-header-dirs ::
|
||||
$(MKDIRS) $(FHS_INCLUDE_DIR)$(FHS_HEADER_FILES_INSTALL_DIR)
|
||||
|
||||
fhs-bin-dirs ::
|
||||
$(MKDIRS) $(FHS_BIN_DIR)
|
||||
|
||||
|
||||
move-headers-to-fhs :: fhs-header-dirs
|
||||
@echo "moving headers to $(FHS_INCLUDE_DIR) .."
|
||||
mv $(GNUSTEP_HEADERS)$(FHS_HEADER_FILES_INSTALL_DIR)/*.h \
|
||||
$(FHS_INCLUDE_DIR)$(FHS_HEADER_FILES_INSTALL_DIR)/
|
||||
|
||||
move-libs-to-fhs ::
|
||||
@echo "moving libs to $(FHS_LIB_DIR) .."
|
||||
mv $(NONFHS_LIBDIR)/$(NONFHS_LIBNAME)* $(FHS_LIB_DIR)/
|
||||
|
||||
move-tools-to-fhs :: fhs-bin-dirs
|
||||
@echo "moving tools from $(NONFHS_BINDIR) to $(FHS_BIN_DIR) .."
|
||||
for i in $(TOOL_NAME); do \
|
||||
mv "$(NONFHS_BINDIR)/$${i}" $(FHS_BIN_DIR); \
|
||||
done
|
||||
|
||||
move-to-fhs :: move-headers-to-fhs move-libs-to-fhs move-tools-to-fhs
|
||||
|
||||
after-install :: move-to-fhs
|
||||
|
||||
endif
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSUserDefaults, NSArray;
|
||||
@class GCSFolderManager;
|
||||
|
||||
@interface Tool : NSObject
|
||||
{
|
||||
NSUserDefaults *ud;
|
||||
GCSFolderManager *folderManager;
|
||||
}
|
||||
|
||||
+ (int)runWithArgs:(NSArray *)_args;
|
||||
- (int)run;
|
||||
|
||||
@end
|
||||
|
||||
#include <GDLContentStore/GCSFolder.h>
|
||||
#include <GDLContentStore/GCSFolderManager.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation Tool
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->ud = [[NSUserDefaults standardUserDefaults] retain];
|
||||
self->folderManager = [[GCSFolderManager defaultFolderManager] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self->ud release];
|
||||
[self->folderManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operation */
|
||||
|
||||
- (int)runOnPath:(NSString *)_path {
|
||||
GCSFolder *folder;
|
||||
NSString *dirname, *filename;
|
||||
NSString *content;
|
||||
|
||||
dirname = [_path stringByDeletingLastPathComponent];
|
||||
filename = [_path lastPathComponent];
|
||||
|
||||
if ((folder = [self->folderManager folderAtPath:dirname]) == nil) {
|
||||
[self logWithFormat:@"did not find folder for file: '%@'", dirname];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((content = [folder fetchContentWithName:filename]) == nil) {
|
||||
[self logWithFormat:@"did not find file: '%@'", _path];
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%s\n", [content cString]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
NSEnumerator *e;
|
||||
NSString *path;
|
||||
|
||||
[self logWithFormat:@"manager: %@", self->folderManager];
|
||||
|
||||
if (![self->folderManager canConnect]) {
|
||||
[self logWithFormat:@"cannot connect folder-info database!"];
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = [[[NSProcessInfo processInfo] argumentsWithoutDefaults]
|
||||
objectEnumerator];
|
||||
[e nextObject]; // skip tool name
|
||||
|
||||
while ((path = [e nextObject]))
|
||||
[self runOnPath:path];
|
||||
|
||||
return 0;
|
||||
}
|
||||
+ (int)runWithArgs:(NSArray *)_args {
|
||||
return [(Tool *)[[[self alloc] init] autorelease] run];
|
||||
}
|
||||
|
||||
@end /* Tool */
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
NSAutoreleasePool *pool;
|
||||
int rc;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
#if LIB_FOUNDATION_LIBRARY
|
||||
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
|
||||
#endif
|
||||
|
||||
rc = [Tool runWithArgs:
|
||||
[[NSProcessInfo processInfo] argumentsWithoutDefaults]];
|
||||
|
||||
[pool release];
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
Copyright (C) 2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSUserDefaults, NSArray;
|
||||
@class GCSFolderManager;
|
||||
|
||||
@interface Tool : NSObject
|
||||
{
|
||||
NSUserDefaults *ud;
|
||||
}
|
||||
|
||||
+ (int)runWithArgs:(NSArray *)_args;
|
||||
- (int)run;
|
||||
|
||||
@end
|
||||
|
||||
#include <GDLContentStore/GCSFolderType.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation Tool
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->ud = [[NSUserDefaults standardUserDefaults] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self->ud release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operation */
|
||||
|
||||
- (int)runOnTable:(NSString *)_tableName typeName:(NSString *)_typeName {
|
||||
GCSFolderType *folderType;
|
||||
|
||||
if ((folderType = [GCSFolderType folderTypeWithName:_typeName]) != nil) {
|
||||
NSString *s;
|
||||
|
||||
s = [folderType sqlQuickCreateWithTableName:_tableName];
|
||||
|
||||
fwrite([s cString], 1, [s cStringLength], stdout);
|
||||
printf("\n");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "ERROR: did not find GCS type: '%s'\n",
|
||||
[_typeName cString]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
NSEnumerator *e;
|
||||
NSString *tableName, *typeName;
|
||||
|
||||
e = [[[NSProcessInfo processInfo] argumentsWithoutDefaults]
|
||||
objectEnumerator];
|
||||
[e nextObject]; // skip tool name
|
||||
|
||||
while ((tableName = [e nextObject]) != nil) {
|
||||
typeName = [e nextObject];
|
||||
if (typeName == nil) {
|
||||
[self logWithFormat:@"got tablename '%@' but no type?!", tableName];
|
||||
break;
|
||||
}
|
||||
|
||||
[self runOnTable:tableName typeName:typeName];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+ (int)runWithArgs:(NSArray *)_args {
|
||||
return [(Tool *)[[[self alloc] init] autorelease] run];
|
||||
}
|
||||
|
||||
@end /* Tool */
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
NSAutoreleasePool *pool;
|
||||
int rc;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
#if LIB_FOUNDATION_LIBRARY
|
||||
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
|
||||
#endif
|
||||
|
||||
rc = [Tool runWithArgs:
|
||||
[[NSProcessInfo processInfo] argumentsWithoutDefaults]];
|
||||
|
||||
[pool release];
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSUserDefaults, NSArray;
|
||||
@class GCSFolderManager;
|
||||
|
||||
@interface Tool : NSObject
|
||||
{
|
||||
NSUserDefaults *ud;
|
||||
GCSFolderManager *folderManager;
|
||||
}
|
||||
|
||||
+ (int)runWithArgs:(NSArray *)_args;
|
||||
- (int)run;
|
||||
|
||||
@end
|
||||
|
||||
#include <GDLContentStore/GCSFolder.h>
|
||||
#include <GDLContentStore/GCSFolderManager.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation Tool
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->ud = [[NSUserDefaults standardUserDefaults] retain];
|
||||
self->folderManager = [[GCSFolderManager defaultFolderManager] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self->ud release];
|
||||
[self->folderManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operation */
|
||||
|
||||
- (int)runOnPath:(NSString *)_path {
|
||||
NSArray *subfolders;
|
||||
unsigned i, count;
|
||||
GCSFolder *folder;
|
||||
|
||||
[self logWithFormat:@"ls path: '%@'", _path];
|
||||
|
||||
#if 0 // we do not necessarily need the whole hierarchy
|
||||
if (![self->folderManager folderExistsAtPath:_path])
|
||||
[self logWithFormat:@"folder does not exist: '%@'", _path];
|
||||
#endif
|
||||
|
||||
subfolders = [self->folderManager
|
||||
listSubFoldersAtPath:_path
|
||||
recursive:[ud boolForKey:@"r"]];
|
||||
if (subfolders == nil) {
|
||||
[self logWithFormat:@"cannot list folder: '%@'", _path];
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0, count = [subfolders count]; i < count; i++) {
|
||||
printf("%s\n", [[subfolders objectAtIndex:i] cString]);
|
||||
}
|
||||
|
||||
folder = [self->folderManager folderAtPath:_path];
|
||||
|
||||
if ([folder isNotNull]) {
|
||||
NSLog(@"folder: %@", folder);
|
||||
|
||||
NSLog(@" can%s connect store: %@", [folder canConnectStore] ? "" : "not",
|
||||
[[folder location] absoluteString]);
|
||||
NSLog(@" can%s connect quick: %@", [folder canConnectQuick] ? "" : "not",
|
||||
[[folder quickLocation] absoluteString]);
|
||||
}
|
||||
else {
|
||||
NSLog(@"ERROR: could not create folder object for path: '%@'", _path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
NSEnumerator *e;
|
||||
NSString *path;
|
||||
|
||||
[self logWithFormat:@"manager: %@", self->folderManager];
|
||||
|
||||
if (![self->folderManager canConnect]) {
|
||||
[self logWithFormat:@"cannot connect folder-info database!"];
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = [[[NSProcessInfo processInfo] argumentsWithoutDefaults]
|
||||
objectEnumerator];
|
||||
[e nextObject]; // skip tool name
|
||||
|
||||
while ((path = [e nextObject]) != nil)
|
||||
[self runOnPath:path];
|
||||
|
||||
return 0;
|
||||
}
|
||||
+ (int)runWithArgs:(NSArray *)_args {
|
||||
return [(Tool *)[[[self alloc] init] autorelease] run];
|
||||
}
|
||||
|
||||
@end /* Tool */
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
NSAutoreleasePool *pool;
|
||||
int rc;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
#if LIB_FOUNDATION_LIBRARY
|
||||
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
|
||||
#endif
|
||||
|
||||
rc = [Tool runWithArgs:
|
||||
[[NSProcessInfo processInfo] argumentsWithoutDefaults]];
|
||||
|
||||
[pool release];
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSUserDefaults, NSArray;
|
||||
@class GCSFolderManager;
|
||||
|
||||
@interface Tool : NSObject
|
||||
{
|
||||
NSUserDefaults *ud;
|
||||
GCSFolderManager *folderManager;
|
||||
}
|
||||
|
||||
+ (int)runWithArgs:(NSArray *)_args;
|
||||
- (int)run;
|
||||
|
||||
@end
|
||||
|
||||
#include <GDLContentStore/GCSFolder.h>
|
||||
#include <GDLContentStore/GCSFolderManager.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation Tool
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->ud = [[NSUserDefaults standardUserDefaults] retain];
|
||||
self->folderManager = [[GCSFolderManager defaultFolderManager] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self->ud release];
|
||||
[self->folderManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operation */
|
||||
|
||||
- (int)runOnPath:(NSString *)_path type:(NSString *)_type {
|
||||
NSException *error;
|
||||
|
||||
[self logWithFormat:@"mkdir %@ at path: '%@'", _type, _path];
|
||||
|
||||
if ([self->folderManager folderExistsAtPath:_path]) {
|
||||
[self logWithFormat:@"folder already exist at path: '%@'", _path];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((error = [self->folderManager createFolderOfType:_type atPath:_path])) {
|
||||
[self logWithFormat:@"creation of folder %@ at %@ failed: %@",
|
||||
_type, _path, error];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ([self->folderManager folderExistsAtPath:_path])
|
||||
[self logWithFormat:@"CREATED."];
|
||||
else
|
||||
[self logWithFormat:@"cannot find fresh folder?"];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
NSEnumerator *e;
|
||||
NSString *type;
|
||||
NSString *path;
|
||||
|
||||
[self logWithFormat:@"manager: %@", self->folderManager];
|
||||
|
||||
if (![self->folderManager canConnect]) {
|
||||
[self logWithFormat:@"cannot connect folder-info database!"];
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = [[[NSProcessInfo processInfo] argumentsWithoutDefaults]
|
||||
objectEnumerator];
|
||||
[e nextObject]; // skip tool name
|
||||
|
||||
type = [[[e nextObject] copy] autorelease];
|
||||
|
||||
while ((path = [e nextObject]))
|
||||
[self runOnPath:path type:type];
|
||||
|
||||
return 0;
|
||||
}
|
||||
+ (int)runWithArgs:(NSArray *)_args {
|
||||
return [(Tool *)[[[self alloc] init] autorelease] run];
|
||||
}
|
||||
|
||||
@end /* Tool */
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
NSAutoreleasePool *pool;
|
||||
int rc;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
#if LIB_FOUNDATION_LIBRARY
|
||||
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
|
||||
#endif
|
||||
|
||||
rc = [Tool runWithArgs:
|
||||
[[NSProcessInfo processInfo] argumentsWithoutDefaults]];
|
||||
|
||||
[pool release];
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSUserDefaults, NSArray;
|
||||
@class GCSFolderManager;
|
||||
|
||||
@interface Tool : NSObject
|
||||
{
|
||||
NSUserDefaults *ud;
|
||||
GCSFolderManager *folderManager;
|
||||
}
|
||||
|
||||
+ (int)runWithArgs:(NSArray *)_args;
|
||||
- (int)run;
|
||||
|
||||
@end
|
||||
|
||||
#include <GDLContentStore/GCSFolder.h>
|
||||
#include <GDLContentStore/GCSFolderManager.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation Tool
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->ud = [[NSUserDefaults standardUserDefaults] retain];
|
||||
self->folderManager = [[GCSFolderManager defaultFolderManager] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[self->ud release];
|
||||
[self->folderManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* operation */
|
||||
|
||||
- (int)runOnPath:(NSString *)_path {
|
||||
GCSFolder *folder;
|
||||
|
||||
[self logWithFormat:@"update quick from store at path: '%@'", _path];
|
||||
|
||||
if (![self->folderManager folderExistsAtPath:_path]) {
|
||||
[self logWithFormat:@"no folder exist at path: '%@'", _path];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((folder = [self->folderManager folderAtPath:_path]) == nil) {
|
||||
[self logWithFormat:@"got no folder object for path: '%@'", _path];
|
||||
return 2;
|
||||
}
|
||||
[self logWithFormat:@" folder: %@", folder];
|
||||
|
||||
// TODO:
|
||||
[self logWithFormat:@" should recreate folder .."];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (int)run {
|
||||
NSEnumerator *e;
|
||||
NSString *path;
|
||||
|
||||
[self logWithFormat:@"manager: %@", self->folderManager];
|
||||
|
||||
if (![self->folderManager canConnect]) {
|
||||
[self logWithFormat:@"cannot connect folder-info database!"];
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = [[[NSProcessInfo processInfo] argumentsWithoutDefaults]
|
||||
objectEnumerator];
|
||||
[e nextObject]; // skip tool name
|
||||
|
||||
while ((path = [e nextObject]))
|
||||
[self runOnPath:path];
|
||||
|
||||
return 0;
|
||||
}
|
||||
+ (int)runWithArgs:(NSArray *)_args {
|
||||
return [(Tool *)[[[self alloc] init] autorelease] run];
|
||||
}
|
||||
|
||||
@end /* Tool */
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
NSAutoreleasePool *pool;
|
||||
int rc;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
#if LIB_FOUNDATION_LIBRARY
|
||||
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
|
||||
#endif
|
||||
|
||||
rc = [Tool runWithArgs:
|
||||
[[NSProcessInfo processInfo] argumentsWithoutDefaults]];
|
||||
|
||||
[pool release];
|
||||
return rc;
|
||||
}
|
Loading…
Reference in New Issue