removed outdated xmlrpc and soap service, it is off by default since couple of versions

This commit is contained in:
Ralf Becker 2014-01-19 10:19:49 +00:00
parent 41abf2cc21
commit edd07a9729
37 changed files with 6 additions and 14079 deletions

View File

@ -295,17 +295,8 @@
</td>
</tr>
-->
<tr class="row_off">
<td>{lang_Enable_the_xmlrpc_service} {lang_(default_No,_leave_it_off_if_you_dont_use_it)}:</td>
<td>
<select name="newsettings[xmlrpc_enabled]">
<option value="">{lang_No}</option>
<option value="True"{selected_xmlrpc_enabled_True}>{lang_Yes}</option>
</select>
</td>
</tr>
<tr class="row_on">
<tr class="row_off">
<td>{lang_Enable_the_soap_service} {lang_(default_No,_leave_it_off_if_you_dont_use_it)}:</td>
<td>
<select name="newsettings[soap_enabled]">
@ -314,19 +305,19 @@
</select>
</td>
</tr>
<tr class="row_off">
<tr class="row_on">
<td>{lang_How_many_entries_should_non-admins_be_able_to_export_(empty_=_no_limit,_no_=_no_export)}:<br />{lang_This_controls_exports_and_merging.}</td>
<td><input name="newsettings[export_limit]" value="{value_export_limit}" size="5"></td>
</tr>
<tr class="row_on">
<tr class="row_off">
<td>{lang_Group_excepted_from_above_export_limit_(admins_are_always_excepted)}:</td>
<td>{call_bo_merge::hook_export_limit_excepted}</td>
</tr>
<tr class="row_off">
<tr class="row_on">
<td>{lang_Allow_remote_administration_from_following_install_ID's_(comma_separated)}:<br />{lang_Own_install_ID:_}{value_install_id}</td>
<td><input name="newsettings[allow_remote_admin]" value="{value_allow_remote_admin}" size="40"></td>
</tr>
<tr class="row_on">
<tr class="row_off">
<td>{lang_Should_exceptions_contain_a_trace_(including_function_arguments)}:</td>
<td>
<select name="newsettings[exception_show_trace]">
@ -335,7 +326,7 @@
</select>
</td>
</tr>
<tr class="row_off">
<tr class="row_on">
<td>{lang_Disable_minifying_of_javascript_and_CSS_files}:</td>
<td>
<select name="newsettings[debug_minify]">

Binary file not shown.

View File

@ -1,505 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML
><HEAD
><TITLE
> Proposal for a Common Groupware Interface Standard
</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"></HEAD
><BODY
CLASS="ARTICLE"
><DIV
CLASS="ARTICLE"
><DIV
CLASS="TITLEPAGE"
><H1
CLASS="TITLE"
><A
NAME="AEN2"
>Proposal for a Common Groupware Interface Standard</A
></H1
><H3
CLASS="AUTHOR"
><A
NAME="AEN4"
></A
></H3
><HR></DIV
><DIV
CLASS="SECT1"
><H2
CLASS="SECT1"
><A
NAME="AEN8"
>Scope</A
></H2
><P
> As many different opensource and freesoftware groupware systems are being developed, the full realization of the dream of a connected world should be prefaced by an agreement to interoperate. There are limited ways in which cooperation with these and commercial groupware systems may be achecived, the majority if not all of which were derived via the establishment of open standards. These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt that while these have proven themselves to be very useful, they are insufficient to satisfy the real needs of a typical business environment.
</P
><P
> This document hopes to provide a reasonable, if limited, recommendation for a set of standardized methods to be used for groupware services interaction. More specifically, it hopes to address the need for such a standard as well as to spur discussion about the common service names and methods themselves.
</P
><P
> Examples will be given for implementations in XML-RPC, since this standard is relatively fixed and open.
</P
><P
> This document does not provide recommendations for the underlying access control system which would allow or deny a particular action.
</P
><P
> Also not discussed here is login and authorization to be used for initial access to a service provider.
</P
></DIV
><DIV
CLASS="SECT1"
><HR><H2
CLASS="SECT1"
><A
NAME="AEN15"
>The Services</A
></H2
><DIV
CLASS="SECT2"
><H3
CLASS="SECT2"
><A
NAME="AEN17"
>Overview</A
></H3
><P
> There are a few common services types that will be needed for minimum useability of a groupware server or application. They are:
</P
><P
></P
><UL
><LI
><P
> Contacts
</P
></LI
><LI
><P
> Schedule
</P
></LI
><LI
><P
> Notes
</P
></LI
><LI
><P
> Todo
</P
></LI
></UL
><P
> These services are represented already in places such as existing groupware client-server applications and also in the PalmOS basic-4 buttons and applications. Different systems may have different names for these services internally, e.g. Contacts - addresses, addressbook, people, Schedule - calendar, agenda, meetings.
</P
><P
> Within each of these services are some common methods that would be called to store, retreive, or update data:
</P
><P
></P
><UL
><LI
><P
> read_list
</P
></LI
><LI
><P
> read
</P
></LI
><LI
><P
> save
</P
></LI
><LI
><P
> delete
</P
></LI
></UL
></DIV
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN40"
>Detail</A
></H3
><DIV
CLASS="SECT3"
><H4
CLASS="SECT3"
><A
NAME="AEN42"
>Contacts</A
></H4
><P
> The concept of contacts may encompass local addressbooks, LDAP, and lists stored in other media. The purpose of the contacts service is not to duplicate or attempt to replace these. In some respects, it might do just that. But its goal is more so to provide a common and shareable way for the other core services to create, edit, and read a common user and address list. All of the other services may use the contact service to obtain record owner information to be used in access control. They would also use them when it is required to share this data, as with a meeting where other local and non-local users will be invited to attend.
</P
><P
> Contacts may include the local installed user base, users on other cooperative servers, or email addresses used for limited cooperation with other groupware services that are not compliant with this service scheme or implementations thereof. It could also include individuals using web-based or local ISP email services. The scope of this document, however, is to define the service with regard to the common methods to be used for server-server and client-server communications:
</P
><P
></P
><UL
><LI
><P
> read_list
</P
></LI
></UL
><P
> This method is used to list contacts, with or without limits, filters, or search criteria. In this way it can be used for simple lists or to search for contact records and their identifiers. The optional search criteria includes:
</P
><P
></P
><OL
TYPE="1"
><LI
><P
> start - Start at this identifier (integer: default 0)
</P
></LI
><LI
><P
> limit - Limit to this number of records returned(integer: unlimited by default)
</P
></LI
><LI
><P
> fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
</P
></LI
><LI
><P
> filter - Show records that are public or private only, or other system-specific filters, e.g group or company(string: default '')
</P
></LI
><LI
><P
> query - Search internal fieldlist for a value (string: default '')
</P
></LI
></OL
><P
> The return for this method includes:
</P
><P
></P
><OL
TYPE="1"
><LI
><P
> count of number of records returned(integer)
</P
></LI
><LI
><P
> array consisting of: array: identifier =&gt; (array: fieldlist key =&gt; value pairs)
</P
></LI
></OL
><P
></P
><UL
><LI
><P
> read
</P
></LI
></UL
><P
> Once the identifier for a single contact record is known, the contact may be read for more detail using this method. This takes two parameters:
</P
><P
></P
><OL
TYPE="1"
><LI
><P
> identifier - (integer: no default)
</P
></LI
><LI
><P
> fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
</P
></LI
></OL
><P
> And returns:
</P
><P
></P
><OL
TYPE="1"
><LI
><P
> array consisting of: array: identifier =&gt; (array: fieldlist key =&gt; value pairs)
</P
></LI
></OL
><P
></P
><UL
><LI
><P
> save
</P
></LI
></UL
><P
> This is a method used to save an existing record or create a new one. If the identifier for an existing record is not passed, a new entry will be created.
</P
><P
></P
><UL
><LI
><P
> delete
</P
></LI
></UL
><P
> This will allow deletion of a record by passing its identifier.
</P
></DIV
><DIV
CLASS="SECT3"
><HR><H4
CLASS="SECT3"
><A
NAME="AEN88"
>Schedule</A
></H4
></DIV
><DIV
CLASS="SECT3"
><HR><H4
CLASS="SECT3"
><A
NAME="AEN90"
>Notes</A
></H4
></DIV
><DIV
CLASS="SECT3"
><HR><H4
CLASS="SECT3"
><A
NAME="AEN92"
>Todo</A
></H4
></DIV
></DIV
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN94"
>Examples in XML-RPC</A
></H3
><P
> Query the contacts service for read_list, using only start and limit to grab the first 5 records, starting with identifier 1. Additionally, return only the firstname and lastname fields n_given and n_family (firstname and lastname in pseudo vcard format):
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;methodCall&#62;
&#60;methodName&#62;service.contacts.read_list&#60;/methodName&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;start&#60;/name&#62;
&#60;value&#62;&#60;string&#62;1&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;limit&#60;/name&#62;
&#60;value&#62;&#60;string&#62;5&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;fields&#60;/name&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;n_given&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n_given&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;n_family&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n_family&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;query&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;filter&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodCall&#62;
</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><DIV
CLASS="SECT1"
><HR><H2
CLASS="SECT1"
><A
NAME="AEN98"
>Conclusion</A
></H2
><P
> This document outlined the following services and methods:
</P
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN101"
>Contacts:</A
></H3
><P
></P
><UL
><LI
><P
> service.contacts.read_list(&lsqb;search criteria&rsqb;)
</P
></LI
><LI
><P
> service.contacts.read(identifier,&lsqb;fieldlist&rsqb;)
</P
></LI
><LI
><P
> service.contacts.save(fields)
</P
></LI
><LI
><P
> service.contacts.delete(identifier)
</P
></LI
></UL
></DIV
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN112"
>Schedule:</A
></H3
><P
></P
><UL
><LI
><P
> service.schedule.read_list(&lsqb;search criteria&rsqb;)
</P
></LI
><LI
><P
> service.schedule.read(identifier,&lsqb;fieldlist&rsqb;)
</P
></LI
><LI
><P
> service.schedule.save(fields)
</P
></LI
><LI
><P
> service.schedule.delete(identifier)
</P
></LI
></UL
></DIV
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN123"
>Notes:</A
></H3
><P
></P
><UL
><LI
><P
> service.notes.read_list(&lsqb;search criteria&rsqb;)
</P
></LI
><LI
><P
> service.notes.read(identifier,&lsqb;fieldlist&rsqb;)
</P
></LI
><LI
><P
> service.notes.save(fields)
</P
></LI
><LI
><P
> service.notes.delete(identifier)
</P
></LI
></UL
></DIV
><DIV
CLASS="SECT2"
><HR><H3
CLASS="SECT2"
><A
NAME="AEN134"
>Todo:</A
></H3
><P
></P
><UL
><LI
><P
> service.todo.read_list(search criteria)
</P
></LI
><LI
><P
> service.todo.read(identifer,&lsqb;fieldlist&rsqb;)
</P
></LI
><LI
><P
> service.todo.save(fields)
</P
></LI
><LI
><P
> service.todo.delete(identifier)
</P
></LI
></UL
></DIV
></DIV
></DIV
></BODY
></HTML
>

View File

@ -1,403 +0,0 @@
#LyX 1.1 created this file. For more info see http://www.lyx.org/
\lyxformat 218
\textclass docbook
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\spacing single
\papersize Default
\paperpackage a4
\use_geometry 0
\use_amsmath 0
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default
\layout Title
Proposal for a Common Groupware Interface Standard
\layout Author
(C) 2001-2004 Miles Lott <milos@groupwhere.org>
\layout Date
September 13, 2001 and December 29, 2003
\layout Standard
\begin_inset LatexCommand \tableofcontents{}
\end_inset
\layout Section
Scope
\layout Standard
As many different opensource and freesoftware groupware systems are being
developed, the full realization of the dream of a connected world should
be prefaced by an agreement to interoperate.
There are limited ways in which cooperation with these and commercial groupware
systems may be achecived, the majority if not all of which were derived
via the establishment of open standards.
These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical
/vcal).
It is felt that while these have proven themselves to be very useful, they
are insufficient to satisfy the real needs of a typical business environment.
\layout Standard
This document hopes to provide a reasonable, if limited, recommendation
for a set of standardized methods to be used for groupware services interaction.
More specifically, it hopes to address the need for such a standard as
well as to spur discussion about the common service names and methods themselve
s.
\layout Standard
Examples will be given for implementations in XML-RPC, since this standard
is relatively fixed and open.
\layout Standard
This document does not provide recommendations for the underlying access
control system which would allow or deny a particular action.
\layout Standard
Also not discussed here is login and authorization to be used for initial
access to a service provider.
\layout Section
The Services
\layout Subsection
Overview
\layout Standard
There are a few common services types that will be needed for minimum useability
of a groupware server or application.
They are:
\layout Itemize
Contacts
\layout Itemize
Schedule
\layout Itemize
Notes
\layout Itemize
Todo
\layout Standard
These services are represented already in places such as existing groupware
client-server applications and also in the PalmOS basic-4 buttons and applicati
ons.
Different systems may have different names for these services internally,
e.g.
Contacts - addresses, addressbook, people, Schedule - calendar, agenda,
meetings.
\layout Standard
Within each of these services are some common methods that would be called
to store, retreive, or update data:
\layout Itemize
read_list
\layout Itemize
read
\layout Itemize
save
\layout Itemize
delete
\layout Subsection
Detail
\layout Subsubsection
Contacts
\layout Standard
The concept of contacts may encompass local addressbooks, LDAP, and lists
stored in other media.
The purpose of the contacts service is not to duplicate or attempt to replace
these.
In some respects, it might do just that.
But its goal is more so to provide a common and shareable way for the other
core services to create, edit, and read a common user and address list.
All of the other services may use the contact service to obtain record
owner information to be used in access control.
They would also use them when it is required to share this data, as with
a meeting where other local and non-local users will be invited to attend.
\layout Standard
Contacts may include the local installed user base, users on other cooperative
servers, or email addresses used for limited cooperation with other groupware
services that are not compliant with this service scheme or implementations
thereof.
It could also include individuals using web-based or local ISP email services.
The scope of this document, however, is to define the service with regard
to the common methods to be used for server-server and client-server communicat
ions:
\layout Itemize
read_list
\layout Standard
This method is used to list contacts, with or without limits, filters, or
search criteria.
In this way it can be used for simple lists or to search for contact records
and their identifiers.
The optional search criteria includes:
\layout Enumerate
start - Start at this identifier (integer: default 0)
\layout Enumerate
limit - Limit to this number of records returned(integer: unlimited by default)
\layout Enumerate
fieldlist - limit to showing only these fields (array: default to identifier,
owner identifier, possibly firstname and lastname)
\layout Enumerate
filter - Show records that are public or private only, or other system-specific
filters, e.g group or company(string: default '')
\layout Enumerate
query - Search internal fieldlist for a value (string: default '')
\layout Standard
The return for this method includes:
\layout Enumerate
count of number of records returned(integer)
\layout Enumerate
array consisting of: array: identifier => (array: fieldlist key => value
pairs)
\layout Itemize
read
\layout Standard
Once the identifier for a single contact record is known, the contact may
be read for more detail using this method.
This takes two parameters:
\layout Enumerate
identifier - (integer: no default)
\layout Enumerate
fieldlist - limit to showing only these fields (array: default to identifier,
owner identifier, possibly firstname and lastname)
\layout Standard
And returns:
\layout Enumerate
array consisting of: array: identifier => (array: fieldlist key => value
pairs)
\layout Itemize
save
\layout Standard
This is a method used to save an existing record or create a new one.
If the identifier for an existing record is not passed, a new entry will
be created.
\layout Itemize
delete
\layout Standard
This will allow deletion of a record by passing its identifier.
\layout Subsubsection
Schedule
\layout Subsubsection
Notes
\layout Subsubsection
Todo
\layout Subsection
Examples in XML-RPC
\layout Standard
Query the contacts service for read_list, using only start and limit to
grab the first 5 records, starting with identifier 1.
Additionally, return only the firstname and lastname fields n_given and
n_family (firstname and lastname in pseudo vcard format):
\layout Code
<methodCall>
\layout Code
<methodName>service.contacts.read_list</methodName>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>start</name>
\layout Code
<value><string>1</string></value>
\layout Code
</member>
\layout Code
<member><name>limit</name>
\layout Code
<value><string>5</string></value>
\layout Code
</member>
\layout Code
<member><name>fields</name>
\layout Code
<value><struct>
\layout Code
<member><name>n_given</name>
\layout Code
<value><string>n_given</string></value>
\layout Code
</member>
\layout Code
<member><name>n_family</name>
\layout Code
<value><string>n_family</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</member>
\layout Code
<member><name>query</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>filter</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodCall>
\layout Section
Conclusion
\layout Standard
This document outlined the following services and methods:
\layout Subsection
Contacts:
\layout Itemize
service.contacts.read_list([search criteria])
\layout Itemize
service.contacts.read(identifier,[fieldlist])
\layout Itemize
service.contacts.save(fields)
\layout Itemize
service.contacts.delete(identifier)
\layout Subsection
Schedule:
\layout Itemize
service.schedule.read_list([search criteria])
\layout Itemize
service.schedule.read(identifier,[fieldlist])
\layout Itemize
service.schedule.save(fields)
\layout Itemize
service.schedule.delete(identifier)
\layout Subsection
Notes:
\layout Itemize
service.notes.read_list([search criteria])
\layout Itemize
service.notes.read(identifier,[fieldlist])
\layout Itemize
service.notes.save(fields)
\layout Itemize
service.notes.delete(identifier)
\layout Subsection
Todo:
\layout Itemize
service.todo.read_list(search criteria)
\layout Itemize
service.todo.read(identifer,[fieldlist])
\layout Itemize
service.todo.save(fields)
\layout Itemize
service.todo.delete(identifier)
\the_end

Binary file not shown.

View File

@ -1,397 +0,0 @@
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
<article lang="en">
<!-- DocBook file was created by LyX 1.1
See http://www.lyx.org/ for more information -->
<artheader>
<title>
Proposal for a Common Groupware Interface Standard
</title>
<author>
(C) 2001-2004 Miles Lott &lt;milos@groupwhere.org&gt;
</author>
<date>
September 13, 2001 and December 29, 2003
</date>
<para>
<toc></toc>
</para>
</artheader>
<sect1>
<title>
Scope
</title>
<para>
As many different opensource and freesoftware groupware systems are being developed, the full realization of the dream of a connected world should be prefaced by an agreement to interoperate. There are limited ways in which cooperation with these and commercial groupware systems may be achecived, the majority if not all of which were derived via the establishment of open standards. These might include email (POP3/IMAP), contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt that while these have proven themselves to be very useful, they are insufficient to satisfy the real needs of a typical business environment.
</para>
<para>
This document hopes to provide a reasonable, if limited, recommendation for a set of standardized methods to be used for groupware services interaction. More specifically, it hopes to address the need for such a standard as well as to spur discussion about the common service names and methods themselves.
</para>
<para>
Examples will be given for implementations in XML-RPC, since this standard is relatively fixed and open.
</para>
<para>
This document does not provide recommendations for the underlying access control system which would allow or deny a particular action.
</para>
<para>
Also not discussed here is login and authorization to be used for initial access to a service provider.
</para>
</sect1>
<sect1>
<title>
The Services
</title>
<sect2>
<title>
Overview
</title>
<para>
There are a few common services types that will be needed for minimum useability of a groupware server or application. They are:
</para>
<itemizedlist>
<listitem>
<para>
Contacts
</para>
</listitem>
<listitem>
<para>
Schedule
</para>
</listitem>
<listitem>
<para>
Notes
</para>
</listitem>
<listitem>
<para>
Todo
</para>
</listitem>
</itemizedlist>
<para>
These services are represented already in places such as existing groupware client-server applications and also in the PalmOS basic-4 buttons and applications. Different systems may have different names for these services internally, e.g. Contacts - addresses, addressbook, people, Schedule - calendar, agenda, meetings.
</para>
<para>
Within each of these services are some common methods that would be called to store, retreive, or update data:
</para>
<itemizedlist>
<listitem>
<para>
read_list
</para>
</listitem>
<listitem>
<para>
read
</para>
</listitem>
<listitem>
<para>
save
</para>
</listitem>
<listitem>
<para>
delete
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>
Detail
</title>
<sect3>
<title>
Contacts
</title>
<para>
The concept of contacts may encompass local addressbooks, LDAP, and lists stored in other media. The purpose of the contacts service is not to duplicate or attempt to replace these. In some respects, it might do just that. But its goal is more so to provide a common and shareable way for the other core services to create, edit, and read a common user and address list. All of the other services may use the contact service to obtain record owner information to be used in access control. They would also use them when it is required to share this data, as with a meeting where other local and non-local users will be invited to attend.
</para>
<para>
Contacts may include the local installed user base, users on other cooperative servers, or email addresses used for limited cooperation with other groupware services that are not compliant with this service scheme or implementations thereof. It could also include individuals using web-based or local ISP email services. The scope of this document, however, is to define the service with regard to the common methods to be used for server-server and client-server communications:
</para>
<itemizedlist>
<listitem>
<para>
read_list
</para>
</listitem>
</itemizedlist>
<para>
This method is used to list contacts, with or without limits, filters, or search criteria. In this way it can be used for simple lists or to search for contact records and their identifiers. The optional search criteria includes:
</para>
<orderedlist>
<listitem>
<para>
start - Start at this identifier (integer: default 0)
</para>
</listitem>
<listitem>
<para>
limit - Limit to this number of records returned(integer: unlimited by default)
</para>
</listitem>
<listitem>
<para>
fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
</para>
</listitem>
<listitem>
<para>
filter - Show records that are public or private only, or other system-specific filters, e.g group or company(string: default '')
</para>
</listitem>
<listitem>
<para>
query - Search internal fieldlist for a value (string: default '')
</para>
</listitem>
</orderedlist>
<para>
The return for this method includes:
</para>
<orderedlist>
<listitem>
<para>
count of number of records returned(integer)
</para>
</listitem>
<listitem>
<para>
array consisting of: array: identifier =&gt; (array: fieldlist key =&gt; value pairs)
</para>
</listitem>
</orderedlist>
<itemizedlist>
<listitem>
<para>
read
</para>
</listitem>
</itemizedlist>
<para>
Once the identifier for a single contact record is known, the contact may be read for more detail using this method. This takes two parameters:
</para>
<orderedlist>
<listitem>
<para>
identifier - (integer: no default)
</para>
</listitem>
<listitem>
<para>
fieldlist - limit to showing only these fields (array: default to identifier, owner identifier, possibly firstname and lastname)
</para>
</listitem>
</orderedlist>
<para>
And returns:
</para>
<orderedlist>
<listitem>
<para>
array consisting of: array: identifier =&gt; (array: fieldlist key =&gt; value pairs)
</para>
</listitem>
</orderedlist>
<itemizedlist>
<listitem>
<para>
save
</para>
</listitem>
</itemizedlist>
<para>
This is a method used to save an existing record or create a new one. If the identifier for an existing record is not passed, a new entry will be created.
</para>
<itemizedlist>
<listitem>
<para>
delete
</para>
</listitem>
</itemizedlist>
<para>
This will allow deletion of a record by passing its identifier.
</para>
</sect3>
<sect3>
<title>
Schedule
</title>
</sect3>
<sect3>
<title>
Notes
</title>
</sect3>
<sect3>
<title>
Todo
</title>
</sect3>
</sect2>
<sect2>
<title>
Examples in XML-RPC
</title>
<para>
Query the contacts service for read_list, using only start and limit to grab the first 5 records, starting with identifier 1. Additionally, return only the firstname and lastname fields n_given and n_family (firstname and lastname in pseudo vcard format):
</para>
<programlisting>
<![ CDATA [<methodCall>
]]><![ CDATA [<methodName>service.contacts.read_list</methodName>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>start</name>
]]><![ CDATA [<value><string>1</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>limit</name>
]]><![ CDATA [<value><string>5</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>fields</name>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>n_given</name>
]]><![ CDATA [<value><string>n_given</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>n_family</name>
]]><![ CDATA [<value><string>n_family</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>query</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>filter</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodCall>
]]> </programlisting>
</sect2>
</sect1>
<sect1>
<title>
Conclusion
</title>
<para>
This document outlined the following services and methods:
</para>
<sect2>
<title>
Contacts:
</title>
<itemizedlist>
<listitem>
<para>
service.contacts.read_list(&lsqb;search criteria&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.contacts.read(identifier,&lsqb;fieldlist&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.contacts.save(fields)
</para>
</listitem>
<listitem>
<para>
service.contacts.delete(identifier)
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>
Schedule:
</title>
<itemizedlist>
<listitem>
<para>
service.schedule.read_list(&lsqb;search criteria&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.schedule.read(identifier,&lsqb;fieldlist&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.schedule.save(fields)
</para>
</listitem>
<listitem>
<para>
service.schedule.delete(identifier)
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>
Notes:
</title>
<itemizedlist>
<listitem>
<para>
service.notes.read_list(&lsqb;search criteria&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.notes.read(identifier,&lsqb;fieldlist&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.notes.save(fields)
</para>
</listitem>
<listitem>
<para>
service.notes.delete(identifier)
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>
Todo:
</title>
<itemizedlist>
<listitem>
<para>
service.todo.read_list(search criteria)
</para>
</listitem>
<listitem>
<para>
service.todo.read(identifer,&lsqb;fieldlist&rsqb;)
</para>
</listitem>
<listitem>
<para>
service.todo.save(fields)
</para>
</listitem>
<listitem>
<para>
service.todo.delete(identifier)
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
</article>

View File

@ -1,293 +0,0 @@
Proposal for a Common Groupware Interface Standard
(C) 2001-2004 Miles Lott <milos@groupwhere.org>
September 13, 2001 and December 29, 2003
Table of Contents
1 Scope
2 The Services
2.1 Overview
2.2 Detail
2.2.1 Contacts
2.2.2 Schedule
2.2.3 Notes
2.2.4 Todo
2.3 Examples in XML-RPC
3 Conclusion
3.1 Contacts:
3.2 Schedule:
3.3 Notes:
3.4 Todo:
1 Scope
As many different opensource and freesoftware groupware systems
are being developed, the full realization of the dream of
a connected world should be prefaced by an agreement to
interoperate. There are limited ways in which cooperation
with these and commercial groupware systems may be achecived,
the majority if not all of which were derived via the establishment
of open standards. These might include email (POP3/IMAP),
contacts(LDAP,vcard), or scheduling(ical/vcal). It is felt
that while these have proven themselves to be very useful,
they are insufficient to satisfy the real needs of a typical
business environment.
This document hopes to provide a reasonable, if limited,
recommendation for a set of standardized methods to be used
for groupware services interaction. More specifically, it
hopes to address the need for such a standard as well as
to spur discussion about the common service names and methods
themselves.
Examples will be given for implementations in XML-RPC, since
this standard is relatively fixed and open.
This document does not provide recommendations for the underlying
access control system which would allow or deny a particular
action.
Also not discussed here is login and authorization to be
used for initial access to a service provider.
2 The Services
2.1 Overview
There are a few common services types that will be needed
for minimum useability of a groupware server or application.
They are:
* Contacts
* Schedule
* Notes
* Todo
These services are represented already in places such as
existing groupware client-server applications and also in
the PalmOS basic-4 buttons and applications. Different systems
may have different names for these services internally,
e.g. Contacts - addresses, addressbook, people, Schedule
- calendar, agenda, meetings.
Within each of these services are some common methods that
would be called to store, retreive, or update data:
* read_list
* read
* save
* delete
2.2 Detail
2.2.1 Contacts
The concept of contacts may encompass local addressbooks,
LDAP, and lists stored in other media. The purpose of the
contacts service is not to duplicate or attempt to replace
these. In some respects, it might do just that. But its
goal is more so to provide a common and shareable way for
the other core services to create, edit, and read a common
user and address list. All of the other services may use
the contact service to obtain record owner information to
be used in access control. They would also use them when
it is required to share this data, as with a meeting where
other local and non-local users will be invited to attend.
Contacts may include the local installed user base, users
on other cooperative servers, or email addresses used for
limited cooperation with other groupware services that are
not compliant with this service scheme or implementations
thereof. It could also include individuals using web-based
or local ISP email services. The scope of this document,
however, is to define the service with regard to the common
methods to be used for server-server and client-server communications:
* read_list
This method is used to list contacts, with or without limits,
filters, or search criteria. In this way it can be used
for simple lists or to search for contact records and their
identifiers. The optional search criteria includes:
1. start - Start at this identifier (integer: default 0)
2. limit - Limit to this number of records returned(integer:
unlimited by default)
3. fieldlist - limit to showing only these fields (array:
default to identifier, owner identifier, possibly firstname
and lastname)
4. filter - Show records that are public or private only,
or other system-specific filters, e.g group or company(string:
default '')
5. query - Search internal fieldlist for a value (string:
default '')
The return for this method includes:
1. count of number of records returned(integer)
2. array consisting of: array: identifier => (array: fieldlist
key => value pairs)
* read
Once the identifier for a single contact record is known,
the contact may be read for more detail using this method.
This takes two parameters:
1. identifier - (integer: no default)
2. fieldlist - limit to showing only these fields (array:
default to identifier, owner identifier, possibly firstname
and lastname)
And returns:
1. array consisting of: array: identifier => (array: fieldlist
key => value pairs)
* save
This is a method used to save an existing record or create
a new one. If the identifier for an existing record is not
passed, a new entry will be created.
* delete
This will allow deletion of a record by passing its identifier.
2.2.2 Schedule
2.2.3 Notes
2.2.4 Todo
2.3 Examples in XML-RPC
Query the contacts service for read_list, using only start
and limit to grab the first 5 records, starting with identifier
1. Additionally, return only the firstname and lastname
fields n_given and n_family (firstname and lastname in pseudo
vcard format):
<methodCall>
<methodName>service.contacts.read_list</methodName>
<params>
<param>
<value><struct>
<member><name>start</name>
<value><string>1</string></value>
</member>
<member><name>limit</name>
<value><string>5</string></value>
</member>
<member><name>fields</name>
<value><struct>
<member><name>n_given</name>
<value><string>n_given</string></value>
</member>
<member><name>n_family</name>
<value><string>n_family</string></value>
</member>
</struct></value>
</member>
<member><name>query</name>
<value><string></string></value>
</member>
<member><name>filter</name>
<value><string></string></value>
</member>
</struct></value>
</param>
</params>
</methodCall>
3 Conclusion
This document outlined the following services and methods:
3.1 Contacts:
* service.contacts.read_list([search criteria])
* service.contacts.read(identifier,[fieldlist])
* service.contacts.save(fields)
* service.contacts.delete(identifier)
3.2 Schedule:
* service.schedule.read_list([search criteria])
* service.schedule.read(identifier,[fieldlist])
* service.schedule.save(fields)
* service.schedule.delete(identifier)
3.3 Notes:
* service.notes.read_list([search criteria])
* service.notes.read(identifier,[fieldlist])
* service.notes.save(fields)
* service.notes.delete(identifier)
3.4 Todo:
* service.todo.read_list(search criteria)
* service.todo.read(identifer,[fieldlist])
* service.todo.save(fields)
* service.todo.delete(identifier)

View File

@ -1,107 +0,0 @@
/* $Id$ */
Perl interfacing to egroupware updated for Frontier-RPC-0.07b4:
The Frontier::RPC module available at CPAN is capable of logging into an
egroupware server. To authenticate your session after the initial login,
however, requires a patch to Frontier. This patch causes Frontier to create
an Authentication header using username/password values. We use the assigned
sessionid and kp3 for this.
NOTE: sessionid/kp3 values in this file are not valid.
TODO:
1. Apply the patch at the end of this file to Frontier-RPC-0.07b4.
2. Install Frontier.
3. Try the following method using rpc-client.pl in the examples subdirectory for
the Frontier source:
rpc-client.pl \
http://www.egroupware.org/egroupware/xmlrpc.php \
system.login \
"{domain => '',username => 'demo', password => 'guest'}"
4. Take the returned sessionid and kp3, e.g.:
$result = HASH(0x826d4b0)
'domain' => 'default'
'kp3' => 'e0219714614769x25bc92286016c60c2'
'sessionid' => '36f9ec1e4ad78bxd8bc902b1c38d3e14'
5. Place these on the commandline for a new request, with sessionid for
username and kp3 for password:
rpc-client.pl \
http://www.egroupware.org/egroupware/xmlrpc.php \
--username 36f9ec1e4ad78bxd8bc902b1c38d3e14 \
--password e0219714614769x25bc92286016c60c2 \
service.contacts.read \
"{ id => '4'}"
6. This should return record #4 from the addressbook application.
Other requests may require different types on the command line, e.g.:
preferences.bosettings.read "addressbook,'','user'"
Here is the patch:
----CUT HERE----
diff -aur Frontier-RPC-0.07b4/examples/rpc-client.pl Frontier-RPC-0.07b4-milos/examples/rpc-client.pl
--- Frontier-RPC-0.07b4/examples/rpc-client.pl 1999-09-02 15:16:49.000000000 -0500
+++ Frontier-RPC-0.07b4-milos/examples/rpc-client.pl 2005-07-30 05:25:36.309201144 -0500
@@ -1,4 +1,4 @@
-#
+#!/usr/bin/perl
# Copyright (C) 1998 Ken MacLeod
# See the file COPYING for distribution terms.
#
@@ -59,7 +59,9 @@
GetOptions( 'debug' => \$debug,
'encoding=s' => \$encoding,
- 'proxy=s' => \$proxy );
+ 'proxy=s' => \$proxy,
+ 'username=s' => \$username,
+ 'password=s' => \$password);
die "usage: rpc-client URL METHOD [\"ARGLIST\"]\n"
if ($#ARGV != 1 && $#ARGV != 2);
@@ -71,12 +73,18 @@
$server = Frontier::Client->new( 'url' => $url,
'debug' => $debug,
'encoding' => $encoding,
- 'proxy' => $proxy );
+ 'proxy' => $proxy,
+ 'username' => $username,
+ 'password' => $password);
+
+use Data::Dumper;
+print Dumper($server);
my @arglist;
eval "\@arglist = ($arglist)";
$result = $server->call ($method, @arglist);
+print Dumper($result);
-require 'dumpvar.pl';
-dumpvar ('main', 'result');
+#require 'dumpvar.pl';
+#dumpvar ('main', 'result');
diff -aur Frontier-RPC-0.07b4/lib/Frontier/Client.pm Frontier-RPC-0.07b4-milos/lib/Frontier/Client.pm
--- Frontier-RPC-0.07b4/lib/Frontier/Client.pm 2002-08-02 19:48:06.000000000 -0500
+++ Frontier-RPC-0.07b4-milos/lib/Frontier/Client.pm 2005-07-30 04:52:35.000000000 -0500
@@ -42,6 +42,11 @@
push @options, 'use_objects' => $self->{'use_objects'};
}
+ if(defined $self->{'username'} and defined $self->{'password'})
+ {
+ use MIME::Base64;
+ $self->{'rq'}->header('Authorization' => 'Basic ' . encode_base64($self->{'username'} . ":" . $self->{'password'}));
+ }
$self->{'enc'} = Frontier::RPC2->new(@options);
return $self;

View File

@ -1,296 +0,0 @@
<HTML
><HEAD
><TITLE
> Business layer requests
</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE=" eGroupWare XML-RPC/SOAP Methodology
"
HREF="phpgw_server.html"><LINK
REL="PREVIOUS"
TITLE=" eGroupWare XML-RPC/SOAP Methodology
"
HREF="phpgw_server.html"><LINK
REL="NEXT"
TITLE=" More to come...
"
HREF="phpgw_server-2.html"></HEAD
><BODY
CLASS="SECT1"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>eGroupWare XML-RPC/SOAP Methodology</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="phpgw_server.html"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="phpgw_server-2.html"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN33"
>Business layer requests</A
></H1
><P
> Once a successful login return packet has been received and sessionid/kp3 have been extracted, every subsequent packet sent to the egroupware server must be preceded by an Authorization header. Here is a sample header:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>POST /egroupware/xmlrpc.php HTTP/1.0
User-Agent: PHP XMLRPC 1.0
Host: my.local.host
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
Content-Type: text/xml
Content-Length: 875
</PRE
></TD
></TR
></TABLE
><P
> The longish string is a base64 encoding of the $sessionid . ':' . $kp3. For now this is our only supported authentication method. Additional methods would probably also affect the methodCalls. This is certainly open to discussion. Following is a typical request for some contact data:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;?xml version="1.0"?&#62;
&#60;methodCall&#62;
&#60;methodName&#62;addressbook.boaddressbook.read_entries&#60;/methodName&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;start&#60;/name&#62;
&#60;value&#62;&#60;string&#62;1&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;limit&#60;/name&#62;
&#60;value&#62;&#60;string&#62;5&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;fields&#60;/name&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;n_given&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n_given&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;n_family&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n_family&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;query&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;filter&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;sort&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;order&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodCall&#62;
</PRE
></TD
></TR
></TABLE
><P
> Successful response:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;?xml version="1.0"?&#62;
&#60;methodResponse&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;0&#60;/name&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;id&#60;/name&#62;
&#60;value&#62;&#60;string&#62;1&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;lid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;tid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;owner&#60;/name&#62;
&#60;value&#62;&#60;string&#62;500&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;access&#60;/name&#62;
&#60;value&#62;&#60;string&#62;private&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;cat_id&#60;/name&#62;
&#60;value&#62;&#60;string&#62;1&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;n_given&#60;/name&#62;
&#60;value&#62;&#60;string&#62;Alan&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;1&#60;/name&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;id&#60;/name&#62;
&#60;value&#62;&#60;string&#62;2&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;lid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;tid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;n&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;owner&#60;/name&#62;
&#60;value&#62;&#60;string&#62;500&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;access&#60;/name&#62;
&#60;value&#62;&#60;string&#62;private&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;cat_id&#60;/name&#62;
&#60;value&#62;&#60;string&#62;1&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;n_given&#60;/name&#62;
&#60;value&#62;&#60;string&#62;Andy&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/member&#62;
...
</PRE
></TD
></TR
></TABLE
><P
> Unauthorized access attempt returns:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;methodResponse&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;string&#62;UNAUTHORIZED&#60;/string&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodResponse&#62;
</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="phpgw_server.html"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="phpgw_server.html"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="phpgw_server-2.html"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>eGroupWare XML-RPC/SOAP Methodology</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>More to come...</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

View File

@ -1,122 +0,0 @@
<HTML
><HEAD
><TITLE
> More to come...
</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE=" eGoupWare XML-RPC/SOAP Methodology
"
HREF="phpgw_server.html"><LINK
REL="PREVIOUS"
TITLE=" Business layer requests
"
HREF="phpgw_server-1.html"></HEAD
><BODY
CLASS="SECT1"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>eGoupWare XML-RPC/SOAP Methodology</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="phpgw_server-1.html"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
>&nbsp;</TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN43"
>More to come...</A
></H1
><P
> Documenting every single call will be difficult, but should be done. In leiu of this, please see the class.bo{APPNAME}.inc.php files in each application/inc directory in the egroupware cvs. In this file will be a list_methods() function, which returns the information to the server about input/output structure for each call. If the file does not have this function, then it is not yet workable via this interface. As for the actual functions, they are also in this file. Generally, they will all accept associative array input and return same, but not always. This code is in flux, have fun.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="phpgw_server-1.html"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="phpgw_server.html"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Business layer requests</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

Binary file not shown.

View File

@ -1,305 +0,0 @@
<HTML
><HEAD
><TITLE
> eGroupWare XML-RPC/SOAP Methodology
</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="NEXT"
TITLE=" Business layer requests
"
HREF="phpgw_server-1.html"></HEAD
><BODY
CLASS="ARTICLE"
><DIV
CLASS="ARTICLE"
><DIV
CLASS="TITLEPAGE"
><H1
CLASS="TITLE"
><A
NAME="AEN2"
>eGroupWare XML-RPC/SOAP Methodology</A
></H1
><H3
CLASS="AUTHOR"
><A
NAME="AEN4"
></A
></H3
><HR></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN8"
>System level requests</A
></H1
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN10"
>Login and authentication</A
></H2
><P
> Authentication for user logins is handled internally no differently than for the typical eGroupWare login via web browser. Server logins, added for XML-RPC and SOAP, are only slightly different. For either protocol, user and server login and authentication and subsequent requests are handled by their respective server apps, xmlrpc.php and soap.php. A server is identified by a custom HTTP header, without which a normal user login will be undertaken.
</P
><P
> A client or server sends the appropriate XML-RPC or SOAP packet containing host, user, and password information to the phpgw server. The server then assigns a sessionid and key, which is returned to the client in the appropriate format.
</P
><P
> Our current method for authenticating requests after successful login is via the Authorization: Basic HTTP header to be sent by the client or requesting server. The format of this header is a base64 encoding of the assigned sessionid and kp3 variables, seperated by a ':'.
</P
><P
> Further security may be obtained by using SSL on the client and server. In the future, we may encrypt/descrypt the data on either end, or at least provide this as an option. The sessionid and key variables will make this possible, and relatively secure.
</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN16"
>system.login</A
></H3
><P
> The first request a client will make is the system.login method. Here is a sample of a server login packet in XML-RPC:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;?xml version="1.0"?&#62;
&#60;methodCall&#62;
&#60;methodName&#62;system.login&#60;/methodName&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;server_name&#60;/name&#62;
&#60;value&#62;&#60;string&#62;my.host.name&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;username&#60;/name&#62;
&#60;value&#62;&#60;string&#62;bubba&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;password&#60;/name&#62;
&#60;value&#62;&#60;string&#62;gump&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62; &#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodCall&#62;
</PRE
></TD
></TR
></TABLE
><P
> And the same in SOAP:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;?xml version="1.0"?&#62;
&#60;SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd"
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62;
&#60;SOAP-ENV:Body&#62; &#60;ns6:system_login&#62;
&#60;server_name xsi:type=":string"&#62;my.host.name&#60;/server_name&#62;
&#60;username xsi:type=":string"&#62;bubba&#60;/username&#62;
&#60;password xsi:type=":string"&#62;gump&#60;/password&#62;
&#60;/ns6:system_login&#62;
&#60;/SOAP-ENV:Body&#62;
&#60;/SOAP-ENV:Envelope&#62;
</PRE
></TD
></TR
></TABLE
><P
> The same style of packet would be required for a user/client login. A successful login should yield the following reply:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;methodResponse&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;sessionid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;cf5c5534307562fc57915608377db007&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;kp3&#60;/name&#62;
&#60;value&#62;&#60;string&#62;2fe54daa11c8d52116788aa3f93cb70e&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodResponse&#62;
</PRE
></TD
></TR
></TABLE
><P
> And a failed login:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;methodResponse&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;GOAWAY&#60;/name&#62;
&#60;value&#62;&#60;string&#62;XOXO&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodResponse&#62;
</PRE
></TD
></TR
></TABLE
><P
> eqweqw
</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN27"
>system.logout</A
></H3
><P
> Logout:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;?xml version="1.0"?&#62;
&#60;methodCall&#62;
&#60;methodName&#62;system.logout&#60;/methodName&#62;
&#60;params&#62; &#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;sessionid&#60;/name&#62;
&#60;value&#62;&#60;string&#62;ea35cac53d2c12bd05caecd97304478a&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;member&#62;&#60;name&#62;kp3&#60;/name&#62;
&#60;value&#62;&#60;string&#62;4f2b256e0da4e7cbbebaac9f1fc8ca4a&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodCall&#62;
</PRE
></TD
></TR
></TABLE
><P
> Logout worked:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#60;methodResponse&#62;
&#60;params&#62;
&#60;param&#62;
&#60;value&#62;&#60;struct&#62;
&#60;member&#62;&#60;name&#62;GOODBYE&#60;/name&#62;
&#60;value&#62;&#60;string&#62;XOXO&#60;/string&#62;&#60;/value&#62;
&#60;/member&#62;
&#60;/struct&#62;&#60;/value&#62;
&#60;/param&#62;
&#60;/params&#62;
&#60;/methodResponse&#62;
</PRE
></TD
></TR
></TABLE
></DIV
></DIV
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="phpgw_server-1.html"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Business layer requests</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

View File

@ -1,713 +0,0 @@
#LyX 1.1 created this file. For more info see http://www.lyx.org/
\lyxformat 218
\textclass docbook
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\spacing single
\papersize Default
\paperpackage a4
\use_geometry 0
\use_amsmath 0
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default
\layout Title
eGroupWare XML-RPC/SOAP Methodology
\layout Author
(C) 2001-2004 Miles Lott
\layout Author
milos@groupwhere.org
\layout Date
August 23, 2001 and December 29, 2003
\layout Standard
additions made September 3, 2001.
\layout Standard
This document is very preliminary, but describes a working system.
\layout Section
System level requests
\layout Subsection
Login and authentication
\layout Standard
Authentication for user logins is handled internally no differently than
for the typical eGroupWare login via web browser.
Server logins, added for XML-RPC and SOAP, are only slightly different.
For either protocol, user and server login and authentication and subsequent
requests are handled by their respective server apps, xmlrpc.php and soap.php.
A server is identified by a custom HTTP header, without which a normal
user login will be undertaken.
\layout Standard
A client or server sends the appropriate XML-RPC or SOAP packet containing
host, user, and password information to the phpgw server.
The server then assigns a sessionid and key, which is returned to the client
in the appropriate format.
\layout Standard
Our current method for authenticating requests after successful login is
via the Authorization: Basic HTTP header to be sent by the client or requesting
server.
The format of this header is a base64 encoding of the assigned sessionid
and kp3 variables, seperated by a ':'.
\layout Standard
Further security may be obtained by using SSL on the client and server.
In the future, we may encrypt/descrypt the data on either end, or at least
provide this as an option.
The sessionid and key variables will make this possible, and relatively
secure.
\layout Subsubsection
system.login
\layout Standard
The first request a client will make is the system.login method.
Here is a sample of a server login packet in XML-RPC:
\layout Code
<?xml version="1.0"?>
\layout Code
<methodCall>
\layout Code
<methodName>system.login</methodName>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>server_name</name>
\layout Code
<value><string>my.host.name</string></value>
\layout Code
</member>
\layout Code
<member><name>username</name>
\layout Code
<value><string>bubba</string></value>
\layout Code
</member>
\layout Code
<member><name>password</name>
\layout Code
<value><string>gump</string></value>
\layout Code
</member> </struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodCall>
\layout Standard
And the same in SOAP:
\layout Code
<?xml version="1.0"?>
\layout Code
<SOAP-ENV:Envelope
\layout Code
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.
org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapi
nterop.org/xsd"
\layout Code
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.o
rg/soap/encoding/">
\layout Code
<SOAP-ENV:Body> <ns6:system_login>
\layout Code
<server_name xsi:type=":string">my.host.name</server_name>
\layout Code
<username xsi:type=":string">bubba</username>
\layout Code
<password xsi:type=":string">gump</password>
\layout Code
</ns6:system_login>
\layout Code
</SOAP-ENV:Body>
\layout Code
</SOAP-ENV:Envelope>
\layout Standard
The same style of packet would be required for a user/client login.
A successful login should yield the following reply:
\layout Code
<methodResponse>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>sessionid</name>
\layout Code
<value><string>cf5c5534307562fc57915608377db007</string></value>
\layout Code
</member>
\layout Code
<member><name>kp3</name>
\layout Code
<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodResponse>
\layout Standard
And a failed login:
\layout Code
<methodResponse>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>GOAWAY</name>
\layout Code
<value><string>XOXO</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodResponse>
\layout Standard
eqweqw
\layout Subsubsection
system.logout
\layout Standard
Logout:
\layout Code
<?xml version="1.0"?>
\layout Code
<methodCall>
\layout Code
<methodName>system.logout</methodName>
\layout Code
<params> <param>
\layout Code
<value><struct>
\layout Code
<member><name>sessionid</name>
\layout Code
<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
\layout Code
</member>
\layout Code
<member><name>kp3</name>
\layout Code
<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodCall>
\layout Standard
Logout worked:
\layout Code
<methodResponse>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>GOODBYE</name>
\layout Code
<value><string>XOXO</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodResponse>
\layout Section
Business layer requests
\layout Standard
Once a successful login return packet has been received and sessionid/kp3
have been extracted, every subsequent packet sent to the egroupware server
must be preceded by an Authorization header.
Here is a sample header:
\layout Code
POST /egroupware/xmlrpc.php HTTP/1.0
\layout Code
User-Agent: PHP XMLRPC 1.0
\layout Code
Host: my.local.host
\layout Code
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE
4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
\layout Code
Content-Type: text/xml
\layout Code
Content-Length: 875
\layout Standard
The longish string is a base64 encoding of the $sessionid .
':' .
$kp3.
For now this is our only supported authentication method.
Additional methods would probably also affect the methodCalls.
This is certainly open to discussion.
Following is a typical request for some contact data:
\layout Code
<?xml version="1.0"?>
\layout Code
<methodCall>
\layout Code
<methodName>addressbook.boaddressbook.read_entries</methodName>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>start</name>
\layout Code
<value><string>1</string></value>
\layout Code
</member>
\layout Code
<member><name>limit</name>
\layout Code
<value><string>5</string></value>
\layout Code
</member>
\layout Code
<member><name>fields</name>
\layout Code
<value><struct>
\layout Code
<member><name>n_given</name>
\layout Code
<value><string>n_given</string></value>
\layout Code
</member>
\layout Code
<member><name>n_family</name>
\layout Code
<value><string>n_family</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</member>
\layout Code
<member><name>query</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>filter</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>sort</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>order</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodCall>
\layout Standard
Successful response:
\layout Code
<?xml version="1.0"?>
\layout Code
<methodResponse>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><struct>
\layout Code
<member><name>0</name>
\layout Code
<value><struct>
\layout Code
<member><name>id</name>
\layout Code
<value><string>1</string></value>
\layout Code
</member>
\layout Code
<member><name>lid</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>tid</name>
\layout Code
<value><string>n</string></value>
\layout Code
</member>
\layout Code
<member><name>owner</name>
\layout Code
<value><string>500</string></value>
\layout Code
</member>
\layout Code
<member><name>access</name>
\layout Code
<value><string>private</string></value>
\layout Code
</member>
\layout Code
<member><name>cat_id</name>
\layout Code
<value><string>1</string></value>
\layout Code
</member>
\layout Code
<member><name>n_given</name>
\layout Code
<value><string>Alan</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</member>
\layout Code
<member><name>1</name>
\layout Code
<value><struct>
\layout Code
<member><name>id</name>
\layout Code
<value><string>2</string></value>
\layout Code
</member>
\layout Code
<member><name>lid</name>
\layout Code
<value><string></string></value>
\layout Code
</member>
\layout Code
<member><name>tid</name>
\layout Code
<value><string>n</string></value>
\layout Code
</member>
\layout Code
<member><name>owner</name>
\layout Code
<value><string>500</string></value>
\layout Code
</member>
\layout Code
<member><name>access</name>
\layout Code
<value><string>private</string></value>
\layout Code
</member>
\layout Code
<member><name>cat_id</name>
\layout Code
<value><string>1</string></value>
\layout Code
</member>
\layout Code
<member><name>n_given</name>
\layout Code
<value><string>Andy</string></value>
\layout Code
</member>
\layout Code
</struct></value>
\layout Code
</member>
\layout Code
...
\layout Standard
Unauthorized access attempt returns:
\layout Code
<methodResponse>
\layout Code
<params>
\layout Code
<param>
\layout Code
<value><string>UNAUTHORIZED</string></value>
\layout Code
</param>
\layout Code
</params>
\layout Code
</methodResponse>
\layout Section
More to come...
\layout Standard
Documenting every single call will be difficult, but should be done.
In leiu of this, please see the class.bo{APPNAME}.inc.php files in each applicatio
n/inc directory in the egroupware cvs.
In this file will be a list_methods() function, which returns the information
to the server about input/output structure for each call.
If the file does not have this function, then it is not yet workable via
this interface.
As for the actual functions, they are also in this file.
Generally, they will all accept associative array input and return same,
but not always.
This code is in flux, have fun.
\the_end

Binary file not shown.

View File

@ -1,568 +0,0 @@
%!PS-Adobe-2.0
%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
%%Title: phpgw_server.dvi
%%Pages: 6
%%PageOrder: Ascend
%%BoundingBox: 0 0 612 792
%%DocumentFonts: Helvetica-Bold Times-Roman Courier Times-Italic
%%EndComments
%DVIPSWebPage: (www.radicaleye.com)
%DVIPSCommandLine: dvips -t letter -o phpgw_server.ps phpgw_server.dvi
%DVIPSParameters: dpi=600, compressed
%DVIPSSource: TeX output 2003.12.28:0956
%%BeginProcSet: texc.pro
%!
/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
(LaserWriter 16/600)]{A length product length le{A length product exch 0
exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
%%EndProcSet
%%BeginProcSet: 8r.enc
% @@psencodingfile@{
% author = "S. Rahtz, P. MacKay, Alan Jeffrey, B. Horn, K. Berry",
% version = "0.6",
% date = "22 June 1996",
% filename = "8r.enc",
% email = "kb@@mail.tug.org",
% address = "135 Center Hill Rd. // Plymouth, MA 02360",
% codetable = "ISO/ASCII",
% checksum = "119 662 4424",
% docstring = "Encoding for TrueType or Type 1 fonts to be used with TeX."
% @}
%
% Idea is to have all the characters normally included in Type 1 fonts
% available for typesetting. This is effectively the characters in Adobe
% Standard Encoding + ISO Latin 1 + extra characters from Lucida.
%
% Character code assignments were made as follows:
%
% (1) the Windows ANSI characters are almost all in their Windows ANSI
% positions, because some Windows users cannot easily reencode the
% fonts, and it makes no difference on other systems. The only Windows
% ANSI characters not available are those that make no sense for
% typesetting -- rubout (127 decimal), nobreakspace (160), softhyphen
% (173). quotesingle and grave are moved just because it's such an
% irritation not having them in TeX positions.
%
% (2) Remaining characters are assigned arbitrarily to the lower part
% of the range, avoiding 0, 10 and 13 in case we meet dumb software.
%
% (3) Y&Y Lucida Bright includes some extra text characters; in the
% hopes that other PostScript fonts, perhaps created for public
% consumption, will include them, they are included starting at 0x12.
%
% (4) Remaining positions left undefined are for use in (hopefully)
% upward-compatible revisions, if someday more characters are generally
% available.
%
% (5) hyphen appears twice for compatibility with both ASCII and Windows.
%
/TeXBase1Encoding [
% 0x00 (encoded characters from Adobe Standard not in Windows 3.1)
/.notdef /dotaccent /fi /fl
/fraction /hungarumlaut /Lslash /lslash
/ogonek /ring /.notdef
/breve /minus /.notdef
% These are the only two remaining unencoded characters, so may as
% well include them.
/Zcaron /zcaron
% 0x10
/caron /dotlessi
% (unusual TeX characters available in, e.g., Lucida Bright)
/dotlessj /ff /ffi /ffl
/.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef
% very contentious; it's so painful not having quoteleft and quoteright
% at 96 and 145 that we move the things normally found there down to here.
/grave /quotesingle
% 0x20 (ASCII begins)
/space /exclam /quotedbl /numbersign
/dollar /percent /ampersand /quoteright
/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
% 0x30
/zero /one /two /three /four /five /six /seven
/eight /nine /colon /semicolon /less /equal /greater /question
% 0x40
/at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O
% 0x50
/P /Q /R /S /T /U /V /W
/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
% 0x60
/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o
% 0x70
/p /q /r /s /t /u /v /w
/x /y /z /braceleft /bar /braceright /asciitilde
/.notdef % rubout; ASCII ends
% 0x80
/.notdef /.notdef /quotesinglbase /florin
/quotedblbase /ellipsis /dagger /daggerdbl
/circumflex /perthousand /Scaron /guilsinglleft
/OE /.notdef /.notdef /.notdef
% 0x90
/.notdef /.notdef /.notdef /quotedblleft
/quotedblright /bullet /endash /emdash
/tilde /trademark /scaron /guilsinglright
/oe /.notdef /.notdef /Ydieresis
% 0xA0
/.notdef % nobreakspace
/exclamdown /cent /sterling
/currency /yen /brokenbar /section
/dieresis /copyright /ordfeminine /guillemotleft
/logicalnot
/hyphen % Y&Y (also at 45); Windows' softhyphen
/registered
/macron
% 0xD0
/degree /plusminus /twosuperior /threesuperior
/acute /mu /paragraph /periodcentered
/cedilla /onesuperior /ordmasculine /guillemotright
/onequarter /onehalf /threequarters /questiondown
% 0xC0
/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
/Egrave /Eacute /Ecircumflex /Edieresis
/Igrave /Iacute /Icircumflex /Idieresis
% 0xD0
/Eth /Ntilde /Ograve /Oacute
/Ocircumflex /Otilde /Odieresis /multiply
/Oslash /Ugrave /Uacute /Ucircumflex
/Udieresis /Yacute /Thorn /germandbls
% 0xE0
/agrave /aacute /acircumflex /atilde
/adieresis /aring /ae /ccedilla
/egrave /eacute /ecircumflex /edieresis
/igrave /iacute /icircumflex /idieresis
% 0xF0
/eth /ntilde /ograve /oacute
/ocircumflex /otilde /odieresis /divide
/oslash /ugrave /uacute /ucircumflex
/udieresis /yacute /thorn /ydieresis
] def
%%EndProcSet
%%BeginProcSet: texps.pro
%!
TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2
index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics
exch def dict begin Encoding{exch dup type/integertype ne{pop pop 1 sub
dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}
ifelse}forall Metrics/Metrics currentdict end def[2 index currentdict
end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{
dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1
roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def
dup[exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}
if}forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}
def end
%%EndProcSet
%%BeginProcSet: special.pro
%!
TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N
/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N
/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N
/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{
/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho
X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B
/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{
/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known
{userdict/md get type/dicttype eq{userdict begin md length 10 add md
maxlength ge{/md md dup length 20 add dict copy def}if end md begin
/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S
atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{
itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll
transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll
curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf
pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}
if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1
-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3
get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip
yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub
neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{
noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop
90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get
neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr
1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr
2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4
-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S
TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{
Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale
}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState
save N userdict maxlength dict begin/magscale true def normalscale
currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts
/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x
psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx
psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub
TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{
psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2
roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath
moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict
begin/SpecialSave save N gsave normalscale currentpoint TR
@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{
CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx
sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR
}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse
CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury
lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N
/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end}
repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N
/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX
currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY
moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X
/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0
1 startangle endangle arc savematrix setmatrix}N end
%%EndProcSet
%%BeginProcSet: color.pro
%!
TeXDict begin/setcmykcolor where{pop}{/setcmykcolor{dup 10 eq{pop
setrgbcolor}{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll
}repeat setrgbcolor pop}ifelse}B}ifelse/TeXcolorcmyk{setcmykcolor}def
/TeXcolorrgb{setrgbcolor}def/TeXcolorgrey{setgray}def/TeXcolorgray{
setgray}def/TeXcolorhsb{sethsbcolor}def/currentcmykcolor where{pop}{
/currentcmykcolor{currentrgbcolor 10}B}ifelse/DC{exch dup userdict exch
known{pop pop}{X}ifelse}B/GreenYellow{0.15 0 0.69 0 setcmykcolor}DC
/Yellow{0 0 1 0 setcmykcolor}DC/Goldenrod{0 0.10 0.84 0 setcmykcolor}DC
/Dandelion{0 0.29 0.84 0 setcmykcolor}DC/Apricot{0 0.32 0.52 0
setcmykcolor}DC/Peach{0 0.50 0.70 0 setcmykcolor}DC/Melon{0 0.46 0.50 0
setcmykcolor}DC/YellowOrange{0 0.42 1 0 setcmykcolor}DC/Orange{0 0.61
0.87 0 setcmykcolor}DC/BurntOrange{0 0.51 1 0 setcmykcolor}DC
/Bittersweet{0 0.75 1 0.24 setcmykcolor}DC/RedOrange{0 0.77 0.87 0
setcmykcolor}DC/Mahogany{0 0.85 0.87 0.35 setcmykcolor}DC/Maroon{0 0.87
0.68 0.32 setcmykcolor}DC/BrickRed{0 0.89 0.94 0.28 setcmykcolor}DC/Red{
0 1 1 0 setcmykcolor}DC/OrangeRed{0 1 0.50 0 setcmykcolor}DC/RubineRed{
0 1 0.13 0 setcmykcolor}DC/WildStrawberry{0 0.96 0.39 0 setcmykcolor}DC
/Salmon{0 0.53 0.38 0 setcmykcolor}DC/CarnationPink{0 0.63 0 0
setcmykcolor}DC/Magenta{0 1 0 0 setcmykcolor}DC/VioletRed{0 0.81 0 0
setcmykcolor}DC/Rhodamine{0 0.82 0 0 setcmykcolor}DC/Mulberry{0.34 0.90
0 0.02 setcmykcolor}DC/RedViolet{0.07 0.90 0 0.34 setcmykcolor}DC
/Fuchsia{0.47 0.91 0 0.08 setcmykcolor}DC/Lavender{0 0.48 0 0
setcmykcolor}DC/Thistle{0.12 0.59 0 0 setcmykcolor}DC/Orchid{0.32 0.64 0
0 setcmykcolor}DC/DarkOrchid{0.40 0.80 0.20 0 setcmykcolor}DC/Purple{
0.45 0.86 0 0 setcmykcolor}DC/Plum{0.50 1 0 0 setcmykcolor}DC/Violet{
0.79 0.88 0 0 setcmykcolor}DC/RoyalPurple{0.75 0.90 0 0 setcmykcolor}DC
/BlueViolet{0.86 0.91 0 0.04 setcmykcolor}DC/Periwinkle{0.57 0.55 0 0
setcmykcolor}DC/CadetBlue{0.62 0.57 0.23 0 setcmykcolor}DC
/CornflowerBlue{0.65 0.13 0 0 setcmykcolor}DC/MidnightBlue{0.98 0.13 0
0.43 setcmykcolor}DC/NavyBlue{0.94 0.54 0 0 setcmykcolor}DC/RoyalBlue{1
0.50 0 0 setcmykcolor}DC/Blue{1 1 0 0 setcmykcolor}DC/Cerulean{0.94 0.11
0 0 setcmykcolor}DC/Cyan{1 0 0 0 setcmykcolor}DC/ProcessBlue{0.96 0 0 0
setcmykcolor}DC/SkyBlue{0.62 0 0.12 0 setcmykcolor}DC/Turquoise{0.85 0
0.20 0 setcmykcolor}DC/TealBlue{0.86 0 0.34 0.02 setcmykcolor}DC
/Aquamarine{0.82 0 0.30 0 setcmykcolor}DC/BlueGreen{0.85 0 0.33 0
setcmykcolor}DC/Emerald{1 0 0.50 0 setcmykcolor}DC/JungleGreen{0.99 0
0.52 0 setcmykcolor}DC/SeaGreen{0.69 0 0.50 0 setcmykcolor}DC/Green{1 0
1 0 setcmykcolor}DC/ForestGreen{0.91 0 0.88 0.12 setcmykcolor}DC
/PineGreen{0.92 0 0.59 0.25 setcmykcolor}DC/LimeGreen{0.50 0 1 0
setcmykcolor}DC/YellowGreen{0.44 0 0.74 0 setcmykcolor}DC/SpringGreen{
0.26 0 0.76 0 setcmykcolor}DC/OliveGreen{0.64 0 0.95 0.40 setcmykcolor}
DC/RawSienna{0 0.72 1 0.45 setcmykcolor}DC/Sepia{0 0.83 1 0.70
setcmykcolor}DC/Brown{0 0.81 1 0.60 setcmykcolor}DC/Tan{0.14 0.42 0.56 0
setcmykcolor}DC/Gray{0 0 0 0.50 setcmykcolor}DC/Black{0 0 0 1
setcmykcolor}DC/White{0 0 0 0 setcmykcolor}DC end
%%EndProcSet
TeXDict begin 40258431 52099146 1000 600 600 (phpgw_server.dvi)
@start /Fa 134[37 3[42 23 1[32 1[42 42 2[23 3[42 42 1[37
42 2[42 8[51 69 3[42 51 1[51 60 1[69 46 4[60 3[55 1[51
10[42 42 42 42 42 42 1[23 1[28 45[{TeXBase1Encoding ReEncodeFont}31
83.022 /Times-Italic rf /Fb 133[45 45 45 45 45 45 45
45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
45 1[45 4[45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
2[45 45 45 1[45 45 45 45 45 1[45 45 45 45 1[45 45 45
45 45 45 45 45 45 45 45 45 45 45 10[45 34[{
TeXBase1Encoding ReEncodeFont}69 74.7198 /Courier rf
/Fc 134[46 3[51 28 46 3[51 51 74 23 2[23 1[51 1[46 50[46
46 2[23 46[{TeXBase1Encoding ReEncodeFont}14 83.022 /Helvetica-Bold
rf /Fd 130[40 1[40 37 42 42 60 42 42 23 32 28 42 42 42
42 65 23 42 1[23 42 42 28 37 42 37 42 37 1[42 6[60 78
1[60 51 46 55 1[46 60 60 74 51 2[28 60 60 46 51 60 55
55 60 6[23 3[42 1[42 42 3[23 21 28 21 2[28 28 28 2[42
32[46 46 2[{TeXBase1Encoding ReEncodeFont}62 83.022 /Times-Roman
rf /Fe 138[61 33 4[61 61 4[28 61 61 1[55 61 55 1[55 20[61
26[55 2[28 46[{TeXBase1Encoding ReEncodeFont}14 99.6264
/Helvetica-Bold rf /Ff 134[66 2[66 73 40 66 47 73 1[73
73 106 33 2[33 3[66 1[66 1[66 13[80 5[100 10[86 14[66
66 66 2[33 46[{TeXBase1Encoding ReEncodeFont}22 119.552
/Helvetica-Bold rf /Fg 134[115 3[126 69 1[80 1[126 126
2[57 3[126 126 1[115 126 2[115 8[138 195 3[138 149 1[138
161 1[172 126 4[161 3[149 1[149 17[57 1[69 45[{
TeXBase1Encoding ReEncodeFont}25 206.584 /Helvetica-Bold
rf end
%%EndProlog
%%BeginSetup
%%Feature: *Resolution 600dpi
TeXDict begin
%%BeginPaperSize: Letter
letter
%%EndPaperSize
%%EndSetup
%%Page: 1 1
1 0 bop Black 0 TeXcolorgray Black Black 711 140 a Fg(eGr)l(oupW)-8
b(are)57 b(XML-RPC/SO)-10 b(AP)1497 409 y(Methodology)-2
826 y Ff(1.)34 b(System)g(le)n(vel)h(requests)396 1114
y Fe(1.1.)28 b(Login)f(and)h(authentication)396 1271
y Fd(Authentication)18 b(for)i(user)g(logins)g(is)h(handled)e
(internally)g(no)g(dif)n(ferently)f(than)i(for)g(the)g(typical)g
(eGroupW)-7 b(are)19 b(login)396 1379 y(via)h(web)h(bro)n(wser)-5
b(.)19 b(Serv)o(er)g(logins,)h(added)f(for)g(XML-RPC)i(and)f(SO)m(AP)-9
b(,)20 b(are)g(only)g(slightly)f(dif)n(ferent.)g(F)o(or)h(either)396
1487 y(protocol,)e(user)j(and)e(serv)o(er)h(login)f(and)h
(authentication)e(and)h(subsequent)g(requests)h(are)g(handled)f(by)g
(their)396 1595 y(respecti)n(v)o(e)g(serv)o(er)h(apps,)f(xmlrpc.php)f
(and)h(soap.php.)f(A)j(serv)o(er)e(is)i(identi\002ed)f(by)f(a)i(custom)
f(HTTP)g(header)m(,)396 1703 y(without)g(which)f(a)i(normal)e(user)h
(login)f(will)i(be)g(undertak)o(en.)396 1853 y(A)g(client)f(or)g(serv)o
(er)f(sends)i(the)f(appropriate)e(XML-RPC)i(or)g(SO)m(AP)h(pack)o(et)f
(containing)e(host,)i(user)m(,)g(and)f(passw)o(ord)396
1961 y(information)f(to)i(the)h(phpgw)d(serv)o(er)-5
b(.)20 b(The)g(serv)o(er)f(then)h(assigns)g(a)h(sessionid)f(and)g(k)o
(e)o(y)-5 b(,)19 b(which)g(is)j(returned)c(to)i(the)396
2068 y(client)g(in)h(the)f(appropriate)e(format.)396
2218 y(Our)i(current)f(method)g(for)g(authenticating)g(requests)g
(after)h(successful)g(login)g(is)h(via)f(the)g(Authorization:)e(Basic)
396 2326 y(HTTP)i(header)f(to)i(be)f(sent)g(by)g(the)g(client)g(or)f
(requesting)g(serv)o(er)-5 b(.)19 b(The)h(format)f(of)h(this)g(header)f
(is)i(a)g(base64)e(encoding)396 2434 y(of)h(the)g(assigned)g(sessionid)
g(and)g(kp3)f(v)n(ariables,)g(seperated)h(by)f(a)i(':'.)396
2583 y(Further)e(security)h(may)g(be)g(obtained)f(by)g(using)h(SSL)h
(on)f(the)g(client)g(and)g(serv)o(er)-5 b(.)19 b(In)h(the)g(future,)f
(we)i(may)396 2691 y(encrypt/descrypt)c(the)k(data)f(on)f(either)h
(end,)g(or)g(at)g(least)h(pro)o(vide)d(this)j(as)g(an)f(option.)f(The)h
(sessionid)g(and)f(k)o(e)o(y)396 2799 y(v)n(ariables)h(will)h(mak)o(e)e
(this)i(possible,)f(and)f(relati)n(v)o(ely)g(secure.)396
3052 y Fc(1.1.1.)24 b(system.login)396 3202 y Fd(The)c(\002rst)h
(request)f(a)g(client)g(will)h(mak)o(e)f(is)h(the)f(system.login)f
(method.)g(Here)h(is)h(a)g(sample)f(of)g(a)g(serv)o(er)f(login)h(pack)o
(et)396 3310 y(in)h(XML-RPC:)396 3490 y Fb(<?xml)44 b(version="1.0"?>)
396 3587 y(<methodCall>)396 3684 y
(<methodName>system.login</methodName>)396 3781 y(<params>)396
3878 y(<param>)396 3976 y(<value><struct>)396 4073 y
(<member><name>server_name</name>)396 4170 y
(<value><string>my.host.name</string></val)o(ue>)396
4267 y(</member>)396 4364 y(<member><name>username</name>)396
4461 y(<value><string>bubba</string></value>)396 4558
y(</member>)396 4655 y(<member><name>password</name>)396
4753 y(<value><string>gump</string></value>)396 4850
y(</member>)g(</struct></value>)396 4947 y(</param>)396
5044 y(</params>)396 5141 y(</methodCall>)p Black 3842
5638 a Fa(1)p Black eop
%%Page: 2 2
2 1 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
Black 396 263 a Fd(And)g(the)g(same)h(in)f(SO)m(AP:)396
444 y Fb(<?xml)44 b(version="1.0"?>)396 541 y(<SOAP-ENV:Envelope)396
638 y(xmlns:SOAP-ENV="http://schemas.xmlsoap.or)o(g/soap)o(/envel)o
(ope/")38 b(xmlns:xsi="http://www.w3.org/1999/XMLSche)o(ma-ins)o
(tance")g(xmlns:xsd="http://www.w3.org/1999/XMLSche)o(ma")h
(xmlns:SOAP-ENC="http://schemas.xmlsoa)o(p.org/)o(soap/e)o(ncodin)o
(g/")g(xmlns:si="http://soapinterop.org/xsd")396 735
y(xmlns:ns6="http://soapinterop.org")g
(SOAP-ENV:encodingStyle="http://schemas.xm)o(lsoap.)o(org/so)o(ap/enc)o
(oding/)o(">)396 832 y(<SOAP-ENV:Body>)k(<ns6:system_login>)396
929 y(<server_name)g(xsi:type=":string">my.host.name</server_)o(name>)
396 1026 y(<username)h(xsi:type=":string">bubba</username>)396
1124 y(<password)g(xsi:type=":string">gump</password>)396
1221 y(</ns6:system_login>)396 1318 y(</SOAP-ENV:Body>)396
1415 y(</SOAP-ENV:Envelope>)396 1703 y Fd(The)20 b(same)g(style)h(of)f
(pack)o(et)g(w)o(ould)f(be)h(required)f(for)g(a)i(user/client)e(login.)
h(A)g(successful)g(login)g(should)f(yield)h(the)396 1811
y(follo)n(wing)f(reply:)396 1991 y Fb(<methodResponse>)396
2088 y(<params>)396 2185 y(<param>)396 2283 y(<value><struct>)396
2380 y(<member><name>sessionid</name>)396 2477 y
(<value><string>cf5c5534307562fc5791560837)o(7db007)o(</stri)o(ng></v)o
(alue>)396 2574 y(</member>)396 2671 y(<member><name>kp3</name>)396
2768 y(<value><string>2fe54daa11c8d52116788aa3f9)o(3cb70e)o(</stri)o
(ng></v)o(alue>)396 2865 y(</member>)396 2962 y(</struct></value>)396
3060 y(</param>)396 3157 y(</params>)396 3254 y(</methodResponse>)396
3542 y Fd(And)h(a)h(f)o(ailed)f(login:)396 3722 y Fb(<methodResponse>)
396 3819 y(<params>)396 3916 y(<param>)396 4014 y(<value><struct>)396
4111 y(<member><name>GOAWAY</name>)396 4208 y
(<value><string>XOXO</string></value>)396 4305 y(</member>)396
4402 y(</struct></value>)396 4499 y(</param>)396 4596
y(</params>)396 4693 y(</methodResponse>)396 4982 y Fd(eqweqw)p
Black 3842 5569 a Fa(2)p Black eop
%%Page: 3 3
3 2 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
Black 396 72 a Fc(1.1.2.)k(system.logout)396 222 y Fd(Logout:)396
402 y Fb(<?xml)44 b(version="1.0"?>)396 499 y(<methodCall>)396
596 y(<methodName>system.logout</methodName>)396 693
y(<params>)g(<param>)396 791 y(<value><struct>)396 888
y(<member><name>sessionid</name>)396 985 y
(<value><string>ea35cac53d2c12bd05caecd973)o(04478a)o(</stri)o(ng></v)o
(alue>)396 1082 y(</member>)396 1179 y(<member><name>kp3</name>)396
1276 y(<value><string>4f2b256e0da4e7cbbebaac9f1f)o(c8ca4a)o(</stri)o
(ng></v)o(alue>)396 1373 y(</member>)396 1471 y(</struct></value>)396
1568 y(</param>)396 1665 y(</params>)396 1762 y(</methodCall>)396
2050 y Fd(Logout)19 b(w)o(ork)o(ed:)396 2230 y Fb(<methodResponse>)396
2327 y(<params>)396 2424 y(<param>)396 2522 y(<value><struct>)396
2619 y(<member><name>GOODBYE</name>)396 2716 y
(<value><string>XOXO</string></value>)396 2813 y(</member>)396
2910 y(</struct></value>)396 3007 y(</param>)396 3104
y(</params>)396 3202 y(</methodResponse>)-2 3876 y Ff(2.)34
b(Business)h(la)n(y)o(er)f(requests)396 4044 y Fd(Once)20
b(a)h(successful)f(login)f(return)g(pack)o(et)h(has)g(been)g(recei)n(v)
o(ed)e(and)i(sessionid/kp3)f(ha)n(v)o(e)g(been)h(e)o(xtracted,)e(e)n(v)
o(ery)396 4152 y(subsequent)h(pack)o(et)g(sent)h(to)g(the)g(egroupw)o
(are)c(serv)o(er)j(must)h(be)g(preceded)e(by)h(an)h(Authorization)d
(header)-5 b(.)19 b(Here)h(is)396 4259 y(a)h(sample)f(header:)396
4440 y Fb(POST)44 b(/egroupware/xmlrpc.php)d(HTTP/1.0)396
4537 y(User-Agent:)i(PHP)i(XMLRPC)e(1.0)396 4634 y(Host:)h
(my.local.host)396 4731 y(Authorization:)f(Basic)h
(ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYz)o(AxZmY6)o(NTU3Y)o(zkyYjB)o
(mNGE4Z)o(DVlOTU)o(zMzI2Y)o(mU2OTQ)o(yNjM3Y)o(jQ=)396
4828 y(Content-Type:)f(text/xml)396 4925 y(Content-Length:)g(875)p
Black 3842 5569 a Fa(3)p Black eop
%%Page: 4 4
4 3 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
Black 396 72 a Fd(The)g(longish)f(string)h(is)h(a)g(base64)e(encoding)f
(of)i(the)h($sessionid)e(.)i(':')f(.)g($kp3.)f(F)o(or)h(no)n(w)f(this)i
(is)g(our)f(only)f(supported)396 180 y(authentication)f(method.)h
(Additional)g(methods)g(w)o(ould)h(probably)d(also)k(af)n(fect)f(the)g
(methodCalls.)f(This)h(is)i(certainly)396 288 y(open)d(to)i
(discussion.)e(F)o(ollo)n(wing)g(is)i(a)g(typical)f(request)f(for)h
(some)g(contact)f(data:)396 468 y Fb(<?xml)44 b(version="1.0"?>)396
566 y(<methodCall>)396 663 y(<methodName>addressbook.boaddressbook.rea)
o(d_entr)o(ies</m)o(ethodN)o(ame>)396 760 y(<params>)396
857 y(<param>)396 954 y(<value><struct>)396 1051 y
(<member><name>start</name>)396 1148 y
(<value><string>1</string></value>)396 1246 y(</member>)396
1343 y(<member><name>limit</name>)396 1440 y
(<value><string>5</string></value>)396 1537 y(</member>)396
1634 y(<member><name>fields</name>)396 1731 y(<value><struct>)396
1828 y(<member><name>n_given</name>)396 1926 y
(<value><string>n_given</string></value>)396 2023 y(</member>)396
2120 y(<member><name>n_family</name>)396 2217 y
(<value><string>n_family</string></value>)396 2314 y(</member>)396
2411 y(</struct></value>)396 2508 y(</member>)396 2605
y(<member><name>query</name>)396 2703 y
(<value><string></string></value>)396 2800 y(</member>)396
2897 y(<member><name>filter</name>)396 2994 y
(<value><string></string></value>)396 3091 y(</member>)396
3188 y(<member><name>sort</name>)396 3285 y
(<value><string></string></value>)396 3383 y(</member>)396
3480 y(<member><name>order</name>)396 3577 y
(<value><string></string></value>)396 3674 y(</member>)396
3771 y(</struct></value>)396 3868 y(</param>)396 3965
y(</params>)396 4063 y(</methodCall>)396 4351 y Fd(Successful)20
b(response:)396 4531 y Fb(<?xml)44 b(version="1.0"?>)396
4628 y(<methodResponse>)396 4725 y(<params>)396 4822
y(<param>)396 4919 y(<value><struct>)396 5016 y(<member><name>0</name>)
396 5114 y(<value><struct>)p Black 3842 5569 a Fa(4)p
Black eop
%%Page: 5 5
5 4 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
Black 396 72 a Fb(<member><name>id</name>)396 170 y
(<value><string>1</string></value>)396 267 y(</member>)396
364 y(<member><name>lid</name>)396 461 y
(<value><string></string></value>)396 558 y(</member>)396
655 y(<member><name>tid</name>)396 752 y
(<value><string>n</string></value>)396 850 y(</member>)396
947 y(<member><name>owner</name>)396 1044 y
(<value><string>500</string></value>)396 1141 y(</member>)396
1238 y(<member><name>access</name>)396 1335 y
(<value><string>private</string></value>)396 1432 y(</member>)396
1530 y(<member><name>cat_id</name>)396 1627 y
(<value><string>1</string></value>)396 1724 y(</member>)396
1821 y(<member><name>n_given</name>)396 1918 y
(<value><string>Alan</string></value>)396 2015 y(</member>)396
2112 y(</struct></value>)396 2209 y(</member>)396 2307
y(<member><name>1</name>)396 2404 y(<value><struct>)396
2501 y(<member><name>id</name>)396 2598 y
(<value><string>2</string></value>)396 2695 y(</member>)396
2792 y(<member><name>lid</name>)396 2889 y
(<value><string></string></value>)396 2987 y(</member>)396
3084 y(<member><name>tid</name>)396 3181 y
(<value><string>n</string></value>)396 3278 y(</member>)396
3375 y(<member><name>owner</name>)396 3472 y
(<value><string>500</string></value>)396 3569 y(</member>)396
3666 y(<member><name>access</name>)396 3764 y
(<value><string>private</string></value>)396 3861 y(</member>)396
3958 y(<member><name>cat_id</name>)396 4055 y
(<value><string>1</string></value>)396 4152 y(</member>)396
4249 y(<member><name>n_given</name>)396 4346 y
(<value><string>Andy</string></value>)396 4444 y(</member>)396
4541 y(</struct></value>)396 4638 y(</member>)396 4735
y(...)396 5023 y Fd(Unauthorized)e(access)j(attempt)f(returns:)p
Black 3842 5569 a Fa(5)p Black eop
%%Page: 6 6
6 5 bop Black 0 TeXcolorgray Black 2413 -132 a Fa(eGr)l(oupW)-8
b(ar)m(e)20 b(XML-RPC/SO)-5 b(AP)20 b(Methodolo)o(gy)p
Black 396 72 a Fb(<methodResponse>)396 170 y(<params>)396
267 y(<param>)396 364 y(<value><string>UNAUTHORIZED</string></val)o
(ue>)396 461 y(</param>)396 558 y(</params>)396 655 y
(</methodResponse>)-2 1164 y Ff(3.)34 b(More)f(to)g(come)r(...)396
1331 y Fd(Documenting)18 b(e)n(v)o(ery)h(single)h(call)h(will)f(be)h
(dif)n(\002cult,)e(b)n(ut)h(should)f(be)h(done.)f(In)h(leiu)h(of)e
(this,)i(please)f(see)h(the)396 1439 y(class.bo{APPN)m(AME}.inc.php)c
(\002les)k(in)g(each)f(application/inc)e(directory)g(in)j(the)f(e)o
(groupw)o(are)d(cvs.)j(In)g(this)h(\002le)396 1547 y(will)g(be)f(a)h
(list_methods\(\))d(function,)g(which)i(returns)f(the)h(information)e
(to)i(the)h(serv)o(er)e(about)g(input/output)f(structure)396
1655 y(for)i(each)g(call.)g(If)g(the)g(\002le)h(does)f(not)g(ha)n(v)o
(e)g(this)g(function,)f(then)g(it)i(is)g(not)f(yet)g(w)o(orkable)f(via)
h(this)h(interf)o(ace.)e(As)i(for)396 1763 y(the)f(actual)g(functions,)
f(the)o(y)g(are)i(also)f(in)g(this)h(\002le.)g(Generally)-5
b(,)18 b(the)o(y)i(will)h(all)f(accept)g(associati)n(v)o(e)g(array)f
(input)h(and)396 1871 y(return)f(same,)h(b)n(ut)h(not)e(al)o(w)o(ays.)i
(This)f(code)g(is)h(in)f(\003ux,)g(ha)n(v)o(e)f(fun.)p
Black 3840 5569 a Fa(6)p Black eop
%%Trailer
end
userdict /end-hook known{end-hook}if
%%EOF

View File

@ -1,311 +0,0 @@
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
<article lang="en">
<!-- DocBook file was created by LyX 1.1
See http://www.lyx.org/ for more information -->
<artheader>
<title>
eGroupWare XML-RPC/SOAP Methodology
</title>
<author>
(C) 2001-2004 Miles Lott
milos@groupwhere.org
</author>
<date>
August 23, 2001 and December 29, 2003
</date>
<para>
additions made September 3, 2001.
</para>
<para>
This document is very preliminary, but describes a working system.
</para>
</artheader>
<sect1>
<title>
System level requests
</title>
<sect2>
<title>
Login and authentication
</title>
<para>
Authentication for user logins is handled internally no differently than for the typical eGroupWare login via web browser. Server logins, added for XML-RPC and SOAP, are only slightly different. For either protocol, user and server login and authentication and subsequent requests are handled by their respective server apps, xmlrpc.php and soap.php. A server is identified by a custom HTTP header, without which a normal user login will be undertaken.
</para>
<para>
A client or server sends the appropriate XML-RPC or SOAP packet containing host, user, and password information to the phpgw server. The server then assigns a sessionid and key, which is returned to the client in the appropriate format.
</para>
<para>
Our current method for authenticating requests after successful login is via the Authorization: Basic HTTP header to be sent by the client or requesting server. The format of this header is a base64 encoding of the assigned sessionid and kp3 variables, seperated by a ':'.
</para>
<para>
Further security may be obtained by using SSL on the client and server. In the future, we may encrypt/descrypt the data on either end, or at least provide this as an option. The sessionid and key variables will make this possible, and relatively secure.
</para>
<sect3>
<title>
system.login
</title>
<para>
The first request a client will make is the system.login method. Here is a sample of a server login packet in XML-RPC:
</para>
<programlisting>
<![ CDATA [<?xml version="1.0"?>
]]><![ CDATA [<methodCall>
]]><![ CDATA [<methodName>system.login</methodName>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>server_name</name>
]]><![ CDATA [<value><string>my.host.name</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>username</name>
]]><![ CDATA [<value><string>bubba</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>password</name>
]]><![ CDATA [<value><string>gump</string></value>
]]><![ CDATA [</member> </struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodCall>
]]> </programlisting>
<para>
And the same in SOAP:
</para>
<programlisting>
<![ CDATA [<?xml version="1.0"?>
]]><![ CDATA [<SOAP-ENV:Envelope
]]><![ CDATA [xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd"
]]><![ CDATA [xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
]]><![ CDATA [<SOAP-ENV:Body> <ns6:system_login>
]]><![ CDATA [<server_name xsi:type=":string">my.host.name</server_name>
]]><![ CDATA [<username xsi:type=":string">bubba</username>
]]><![ CDATA [<password xsi:type=":string">gump</password>
]]><![ CDATA [</ns6:system_login>
]]><![ CDATA [</SOAP-ENV:Body>
]]><![ CDATA [</SOAP-ENV:Envelope>
]]> </programlisting>
<para>
The same style of packet would be required for a user/client login. A successful login should yield the following reply:
</para>
<programlisting>
<![ CDATA [<methodResponse>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>sessionid</name>
]]><![ CDATA [<value><string>cf5c5534307562fc57915608377db007</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>kp3</name>
]]><![ CDATA [<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodResponse>
]]> </programlisting>
<para>
And a failed login:
</para>
<programlisting>
<![ CDATA [<methodResponse>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>GOAWAY</name>
]]><![ CDATA [<value><string>XOXO</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodResponse>
]]> </programlisting>
<para>
eqweqw
</para>
</sect3>
<sect3>
<title>
system.logout
</title>
<para>
Logout:
</para>
<programlisting>
<![ CDATA [<?xml version="1.0"?>
]]><![ CDATA [<methodCall>
]]><![ CDATA [<methodName>system.logout</methodName>
]]><![ CDATA [<params> <param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>sessionid</name>
]]><![ CDATA [<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>kp3</name>
]]><![ CDATA [<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodCall>
]]> </programlisting>
<para>
Logout worked:
</para>
<programlisting>
<![ CDATA [<methodResponse>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>GOODBYE</name>
]]><![ CDATA [<value><string>XOXO</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodResponse>
]]> </programlisting>
</sect3>
</sect2>
</sect1>
<sect1>
<title>
Business layer requests
</title>
<para>
Once a successful login return packet has been received and sessionid/kp3 have been extracted, every subsequent packet sent to the egroupware server must be preceded by an Authorization header. Here is a sample header:
</para>
<programlisting>
<![ CDATA [POST /egroupware/xmlrpc.php HTTP/1.0
]]><![ CDATA [User-Agent: PHP XMLRPC 1.0
]]><![ CDATA [Host: my.local.host
]]><![ CDATA [Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
]]><![ CDATA [Content-Type: text/xml
]]><![ CDATA [Content-Length: 875
]]> </programlisting>
<para>
The longish string is a base64 encoding of the &dollar;sessionid . ':' . &dollar;kp3. For now this is our only supported authentication method. Additional methods would probably also affect the methodCalls. This is certainly open to discussion. Following is a typical request for some contact data:
</para>
<programlisting>
<![ CDATA [<?xml version="1.0"?>
]]><![ CDATA [<methodCall>
]]><![ CDATA [<methodName>addressbook.boaddressbook.read_entries</methodName>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>start</name>
]]><![ CDATA [<value><string>1</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>limit</name>
]]><![ CDATA [<value><string>5</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>fields</name>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>n_given</name>
]]><![ CDATA [<value><string>n_given</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>n_family</name>
]]><![ CDATA [<value><string>n_family</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>query</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>filter</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>sort</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>order</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodCall>
]]> </programlisting>
<para>
Successful response:
</para>
<programlisting>
<![ CDATA [<?xml version="1.0"?>
]]><![ CDATA [<methodResponse>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>0</name>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>id</name>
]]><![ CDATA [<value><string>1</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>lid</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>tid</name>
]]><![ CDATA [<value><string>n</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>owner</name>
]]><![ CDATA [<value><string>500</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>access</name>
]]><![ CDATA [<value><string>private</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>cat_id</name>
]]><![ CDATA [<value><string>1</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>n_given</name>
]]><![ CDATA [<value><string>Alan</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>1</name>
]]><![ CDATA [<value><struct>
]]><![ CDATA [<member><name>id</name>
]]><![ CDATA [<value><string>2</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>lid</name>
]]><![ CDATA [<value><string></string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>tid</name>
]]><![ CDATA [<value><string>n</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>owner</name>
]]><![ CDATA [<value><string>500</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>access</name>
]]><![ CDATA [<value><string>private</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>cat_id</name>
]]><![ CDATA [<value><string>1</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [<member><name>n_given</name>
]]><![ CDATA [<value><string>Andy</string></value>
]]><![ CDATA [</member>
]]><![ CDATA [</struct></value>
]]><![ CDATA [</member>
]]><![ CDATA [...
]]> </programlisting>
<para>
Unauthorized access attempt returns:
</para>
<programlisting>
<![ CDATA [<methodResponse>
]]><![ CDATA [<params>
]]><![ CDATA [<param>
]]><![ CDATA [<value><string>UNAUTHORIZED</string></value>
]]><![ CDATA [</param>
]]><![ CDATA [</params>
]]><![ CDATA [</methodResponse>
]]> </programlisting>
</sect1>
<sect1>
<title>
More to come...
</title>
<para>
Documenting every single call will be difficult, but should be done. In leiu of this, please see the class.bo&lcub;APPNAME&rcub;.inc.php files in each application/inc directory in the egroupware cvs. In this file will be a list_methods() function, which returns the information to the server about input/output structure for each call. If the file does not have this function, then it is not yet workable via this interface. As for the actual functions, they are also in this file. Generally, they will all accept associative array input and return same, but not always. This code is in flux, have fun.
</para>
</sect1>
</article>

View File

@ -1,293 +0,0 @@
eGroupWare XML-RPC/SOAP Methodology
(C) 2001-2004 Miles Lott
milos@groupwhere.org
August 23, 2001 and December 29, 2003
additions made September 3, 2001.
This document is very preliminary, but describes a working
system.
1 System level requests
1.1 Login and authentication
Authentication for user logins is handled internally no differently
than for the typical eGroupWare login via web browser. Server
logins, added for XML-RPC and SOAP, are only slightly different.
For either protocol, user and server login and authentication
and subsequent requests are handled by their respective
server apps, xmlrpc.php and soap.php. A server is identified
by a custom HTTP header, without which a normal user login
will be undertaken.
A client or server sends the appropriate XML-RPC or SOAP
packet containing host, user, and password information to
the egroupware server. The server then assigns a sessionid and
key, which is returned to the client in the appropriate
format.
Our current method for authenticating requests after successful
login is via the Authorization: Basic HTTP header to be
sent by the client or requesting server. The format of this
header is a base64 encoding of the assigned sessionid and
kp3 variables, seperated by a ':'.
Further security may be obtained by using SSL on the client
and server. In the future, we may encrypt/decrypt the data
on either end, or at least provide this as an option. The
sessionid and key variables will make this possible, and
relatively secure.
1.1.1 system.login
The first request a client will make is the system.login
method. Here is a sample of a server login packet in XML-RPC:
<?xml version="1.0"?>
<methodCall>
<methodName>system.login</methodName>
<params>
<param>
<value><struct>
<member><name>server_name</name>
<value><string>my.host.name</string></value>
</member>
<member><name>username</name>
<value><string>bubba</string></value>
</member>
<member><name>password</name>
<value><string>gump</string></value>
</member> </struct></value>
</param>
</params>
</methodCall>
And the same in SOAP:
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd"
xmlns:ns6="http://soapinterop.org" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body> <ns6:system_login>
<server_name xsi:type=":string">my.host.name</server_name>
<username xsi:type=":string">bubba</username>
<password xsi:type=":string">gump</password>
</ns6:system_login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The same style of packet would be required for a user/client
login. A successful login should yield the following reply:
<methodResponse>
<params>
<param>
<value><struct>
<member><name>sessionid</name>
<value><string>cf5c5534307562fc57915608377db007</string></value>
</member>
<member><name>kp3</name>
<value><string>2fe54daa11c8d52116788aa3f93cb70e</string></value>
</member>
</struct></value>
</param>
</params>
</methodResponse>
And a failed login:
<methodResponse>
<params>
<param>
<value><struct>
<member><name>GOAWAY</name>
<value><string>XOXO</string></value>
</member>
</struct></value>
</param>
</params>
</methodResponse>
1.1.2 system.logout
Logout:
<?xml version="1.0"?>
<methodCall>
<methodName>system.logout</methodName>
<params> <param>
<value><struct>
<member><name>sessionid</name>
<value><string>ea35cac53d2c12bd05caecd97304478a</string></value>
</member>
<member><name>kp3</name>
<value><string>4f2b256e0da4e7cbbebaac9f1fc8ca4a</string></value>
</member>
</struct></value>
</param>
</params>
</methodCall>
Logout worked:
<methodResponse>
<params>
<param>
<value><struct>
<member><name>GOODBYE</name>
<value><string>XOXO</string></value>
</member>
</struct></value>
</param>
</params>
</methodResponse>
2 Business layer requests
Once a successful login return packet has been received and
sessionid/kp3 have been extracted, every subsequent packet
sent to the egroupware server must be preceded by an Authorization
header. Here is a sample header:
POST /egroupware/xmlrpc.php HTTP/1.0
User-Agent: PHP XMLRPC 1.0
Host: my.local.host
Authorization: Basic ZDgxNDIyZDRkYjg5NDEyNGNiMzZlMDhhZTdlYzAxZmY6NTU3YzkyYjBmNGE4ZDVlOTUzMzI2YmU2OTQyNjM3YjQ=
Content-Type: text/xml
Content-Length: 875
The longish string is a base64 encoding of the $sessionid
. ':' . $kp3. For now this is our only supported authentication
method. Additional methods would probably also affect the
methodCalls. This is certainly open to discussion. Following
is a typical request for some contact data:
<?xml version="1.0"?>
<methodCall>
<methodName>addressbook.boaddressbook.read_entries</methodName>
<params>
<param>
<value><struct>
<member><name>start</name>
<value><string>1</string></value>
</member>
<member><name>limit</name>
<value><string>5</string></value>
</member>
<member><name>fields</name>
<value><struct>
<member><name>n_given</name>
<value><string>n_given</string></value>
</member>
<member><name>n_family</name>
<value><string>n_family</string></value>
</member>
</struct></value>
</member>
<member><name>query</name>
<value><string></string></value>
</member>
<member><name>filter</name>
<value><string></string></value>
</member>
<member><name>sort</name>
<value><string></string></value>
</member>
<member><name>order</name>
<value><string></string></value>
</member>
</struct></value>
</param>
</params>
</methodCall>
Successful response:
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><struct>
<member><name>0</name>
<value><struct>
<member><name>id</name>
<value><string>1</string></value>
</member>
<member><name>lid</name>
<value><string></string></value>
</member>
<member><name>tid</name>
<value><string>n</string></value>
</member>
<member><name>owner</name>
<value><string>500</string></value>
</member>
<member><name>access</name>
<value><string>private</string></value>
</member>
<member><name>cat_id</name>
<value><string>1</string></value>
</member>
<member><name>n_given</name>
<value><string>Alan</string></value>
</member>
</struct></value>
</member>
<member><name>1</name>
<value><struct>
<member><name>id</name>
<value><string>2</string></value>
</member>
<member><name>lid</name>
<value><string></string></value>
</member>
<member><name>tid</name>
<value><string>n</string></value>
</member>
<member><name>owner</name>
<value><string>500</string></value>
</member>
<member><name>access</name>
<value><string>private</string></value>
</member>
<member><name>cat_id</name>
<value><string>1</string></value>
</member>
<member><name>n_given</name>
<value><string>Andy</string></value>
</member>
</struct></value>
</member>
...
Unauthorized access attempt returns:
<methodResponse>
<params>
<param>
<value><string>UNAUTHORIZED</string></value>
</param>
</params>
</methodResponse>
3 More to come...
Documenting every single call will be difficult, but should
be done. In leiu of this, please see the class.bo{APPNAME}.inc.php
files in each application/inc directory in the egroupware
cvs. In this file will be a list_methods() function, which
returns the information to the server about input/output
structure for each call. If the file does not have this
function, then it is not yet workable via this interface.
As for the actual functions, they are also in this file.
Generally, they will all accept associative array input
and return same, but not always. This code is in flux, have
fun.

View File

@ -1,40 +0,0 @@
#!/usr/bin/python
# $Id$
from xmlrpclib import *
import sys
server = Server("http://www.egroupware.org/egroupware/xmlrpc.php");
try:
print "Listing methods:\n"
r = server.system.listMethods();
print r
print "\nTrying to login:\n"
up = {'domain': 'default', 'username': 'demo', 'password': 'guest'}
l = server.system.login(up);
print l
print "\nTrying name/age struct/array test:\n"
# name/age example. this exercises structs and arrays
a = [ {'name': 'Dave', 'age': 35}, {'name': 'Edd', 'age': 45 },
{'name': 'Fred', 'age': 23}, {'name': 'Barney', 'age': 36 }]
r = server.examples.sortByAge(a)
print r
print "\nTrying base 64 test:\n"
# test base 64
b = Binary("Mary had a little lamb She tied it to a pylon")
b.encode(sys.stdout)
r = server.examples.decode64(b)
print r
print "\nTrying to logout:\n"
sk = {'sessionid': l['sessionid'], 'kp3': l['kp3']}
r = server.system.logout(sk);
print r
except Error, v:
print "XML-RPC Error:",v

View File

@ -1,225 +0,0 @@
<?php
/*
SOAPx4
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
This project began based on code from the 2 projects below,
and still contains some original code. The licenses of both must be respected.
XML-RPC for PHP
originally by Edd Dumbill (C) 1999-2000
SOAP for PHP
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
*/
/* changelog:
2001-07-04
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
solidification.)
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
- implemented a transport argument into send() that allows you to specify different transports
(assuming you have implemented the function, and added it to the conditional statement in send()
- abstracted the determination of charset in Content-type header
2001-07-5
- fixed more weird type/namespace issues
*/
// $path can be a complete endpoint url, with the other parameters left blank:
// $soap_client = new soap_client("http://path/to/soap/server");
/* $Id$ */
class soap_client
{
function soap_client($path,$server=False,$port=False)
{
$this->port = 80;
$this->path = $path;
$this->server = $server;
$this->errno;
$this->errstring;
$this->debug_flag = True;
$this->debug_str = '';
$this->username = '';
$this->password = '';
$this->action = '';
$this->incoming_payload = '';
$this->outgoing_payload = '';
$this->response = '';
$this->action = '';
// endpoint mangling
if(preg_match('/'."^http:\\/\\/".'/',$path))
{
$path = str_replace('http://','',$path);
$this->path = strstr($path,'/');
$this->debug("path = $this->path");
if(preg_match('/:/',$path))
{
$this->server = substr($path,0,strpos($path,':'));
$this->port = substr(strstr($path,':'),1);
$this->port = substr($this->port,0,strpos($this->port,'/'));
}
else
{
$this->server = substr($path,0,strpos($path,'/'));
}
}
if($port)
{
$this->port = $port;
}
}
function setCredentials($u, $p)
{
$this->username = $u;
$this->password = $p;
}
function send($msg, $action, $timeout=0, $ssl=False)
{
// where msg is an soapmsg
$msg->debug_flag = $this->debug_flag;
$this->action = $action;
if($ssl)
{
return $this->ssl_sendPayloadHTTP10(
$msg,
$this->server,
$this->port,
$timeout,
$this->username,
$this->password
);
}
else
{
return $this->sendPayloadHTTP10(
$msg,
$this->server,
$this->port,
$timeout,
$this->username,
$this->password
);
}
}
function sendPayloadHTTP10($msg, $server, $port, $timeout=0, $username='', $password='')
{
if($timeout > 0)
{
$fp = fsockopen($server, $port,&$this->errno, &$this->errstr, $timeout);
}
else
{
$fp = fsockopen($server, $port,&$this->errno, &$this->errstr);
}
if (!$fp)
{
$this->debug("Couldn't open socket connection to server!");
$this->debug("Server: $this->server");
return 0;
}
// thanks to Grant Rauscher <grant7@firstworld.net> for this
$credentials = '';
if ($username != '')
{
$credentials = "Authorization: Basic " . base64_encode($username . ":" . $password) . "\r\n";
}
$soap_data = $msg->serialize();
$this->outgoing_payload = 'POST '
. $this->path
. " HTTP/1.0\r\n"
. 'User-Agent: eGroupware/' . $cliversion . '(PHP) ' . "\r\n"
. 'X-EGW-Server: ' . $this->server . "\r\n"
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
. 'Host: '.$this->server . "\r\n"
. $credentials
. "Content-Type: text/xml\r\nContent-Length: " . strlen($soap_data) . "\r\n"
. 'SOAPAction: "' . $this->action . '"' . "\r\n\r\n"
. $soap_data;
// send
if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload)))
{
$this->debug('Write error');
}
// get reponse
while($data = fread($fp, 32768))
{
$incoming_payload .= $data;
}
fclose($fp);
$this->incoming_payload = $incoming_payload;
// $response is a soapmsg object
$this->response = $msg->parseResponse($incoming_payload);
$this->debug($msg->debug_str);
return $this->response;
}
function ssl_sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
{
if(!function_exists(curl_init))
{
$this->errstr = 'No curl functions available - use of ssl is invalid';
return False;
}
/* curl Method borrowed from:
http://sourceforge.net/tracker/index.php?func=detail&aid=427359&group_id=23199&atid=377731
*/
// thanks to Grant Rauscher <grant7@firstworld.net>
// for this
$credentials = '';
if ($username!='')
{
$credentials = "Authorization: Basic " . base64_encode($username . ':' . $password) . "\r\n";
}
$soap_data = $msg->serialize();
$this->outgoing_payload = 'POST '
. $this->path
. " HTTP/1.0\r\n"
. 'User-Agent: eGroupware/' . $cliversion . '(PHP) ' . "\r\n"
. 'X-EGW-Server: ' . $this->server . "\r\n"
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
. 'Host: ' . $this->server . "\r\n"
. $credentials
. "Content-Type: text/xml\r\nContent-Length: " . strlen($soap_data) . "\r\n"
. 'SOAPAction: "' . $this->action . '"' . "\r\n\r\n"
. $soap_data;
// send
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$this->server);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
curl_setopt($ch, CURLOPT_HEADER, 0);
$incoming_payload = curl_exec($ch);
curl_close($ch);
$this->incoming_payload = $incoming_payload;
// $response is a soapmsg object
$this->response = $msg->parseResponse($incoming_payload);
$this->debug($msg->debug_str);
return $this->response;
}
function debug($string)
{
if($this->debug_flag)
{
$this->debug_str .= "$string\n";
}
}
} // end class soap_client
?>

View File

@ -1,375 +0,0 @@
<?php
/* $Id$ */
class soap_parser
{
function soap_parser($xml='',$encoding='UTF-8')
{
global $soapTypes;
$this->soapTypes = $soapTypes;
$this->xml = $xml;
$this->xml_encoding = $encoding;
$this->root_struct = "";
// options: envelope,header,body,method
// determines where in the message we are (envelope,header,body,method)
$this->status = '';
$this->position = 0;
$this->pos_stat = 0;
$this->depth = 0;
$this->default_namespace = '';
$this->namespaces = array();
$this->message = array();
$this->fault = false;
$this->fault_code = '';
$this->fault_str = '';
$this->fault_detail = '';
$this->eval_str = '';
$this->depth_array = array();
$this->debug_flag = True;
$this->debug_str = '';
$this->previous_element = '';
$this->entities = array (
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
"'" => '&apos;',
'"' => '&quot;'
);
// Check whether content has been read.
if(!empty($xml))
{
$this->debug('Entering soap_parser()');
//$this->debug("DATA DUMP:\n\n$xml");
// Create an XML parser.
$this->parser = xml_parser_create($this->xml_encoding);
// Set the options for parsing the XML data.
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
// Set the object for the parser.
xml_set_object($this->parser, &$this);
// Set the element handlers for the parser.
xml_set_element_handler($this->parser, 'start_element','end_element');
xml_set_character_data_handler($this->parser,'character_data');
xml_set_default_handler($this->parser, 'default_handler');
// Parse the XML file.
if(!xml_parse($this->parser,$xml,true))
{
// Display an error message.
$this->debug(sprintf("XML error on line %d: %s",
xml_get_current_line_number($this->parser),
xml_error_string(xml_get_error_code($this->parser))));
$this->fault = true;
}
else
{
// get final eval string
$this->eval_str = "\$response = ".trim($this->build_eval($this->root_struct)).";";
}
xml_parser_free($this->parser);
}
else
{
$this->debug("xml was empty, didn't parse!");
}
}
// loop through msg, building eval_str
function build_eval($pos)
{
$this->debug("inside build_eval() for $pos: ".$this->message[$pos]["name"]);
$eval_str = $this->message[$pos]['eval_str'];
// loop through children, building...
if($this->message[$pos]['children'] != '')
{
$this->debug('children string = '.$this->message[$pos]['children']);
$children = explode('|',$this->message[$pos]['children']);
$this->debug('it has '.count($children).' children');
@reset($children);
while(list($c,$child_pos) = @each($children))
/* foreach($children as $c => $child_pos) */
{
//$this->debug("child pos $child_pos: ".$this->message[$child_pos]["name"]);
if($this->message[$child_pos]['eval_str'] != '')
{
$this->debug('entering build_eval() for '.$this->message[$child_pos]['name'].", array pos $c, pos: $child_pos");
$eval_str .= $this->build_eval($child_pos).', ';
}
}
$eval_str = substr($eval_str,0,strlen($eval_str)-2);
}
// add current node's eval_str
$eval_str .= $this->message[$pos]['end_eval_str'];
return $eval_str;
}
// start-element handler
function start_element($parser, $name, $attrs)
{
// position in a total number of elements, starting from 0
// update class level pos
$pos = $this->position++;
// and set mine
$this->message[$pos]['pos'] = $pos;
// parent/child/depth determinations
// depth = how many levels removed from root?
// set mine as current global depth and increment global depth value
$this->message[$pos]['depth'] = $this->depth++;
// else add self as child to whoever the current parent is
if($pos != 0)
{
$this->message[$this->parent]['children'] .= "|$pos";
}
// set my parent
$this->message[$pos]['parent'] = $this->parent;
// set self as current value for this depth
$this->depth_array[$this->depth] = $pos;
// set self as current parent
$this->parent = $pos;
// set status
if(preg_match('/'.":Envelope$".'/',$name))
{
$this->status = 'envelope';
}
elseif(preg_match('/'.":Header$".'/',$name))
{
$this->status = 'header';
}
elseif(preg_match('/'.":Body$".'/',$name))
{
$this->status = 'body';
// set method
}
elseif($this->status == 'body')
{
$this->status = 'method';
if(preg_match('/:/',$name))
{
$this->root_struct_name = substr(strrchr($name,':'),1);
}
else
{
$this->root_struct_name = $name;
}
$this->root_struct = $pos;
$this->message[$pos]['type'] = 'struct';
}
// set my status
$this->message[$pos]['status'] = $this->status;
// set name
$this->message[$pos]['name'] = htmlspecialchars($name);
// set attrs
$this->message[$pos]['attrs'] = $attrs;
// get namespace
if(preg_match('/'.":".'/',$name))
{
$namespace = substr($name,0,strpos($name,':'));
$this->message[$pos]['namespace'] = $namespace;
$this->default_namespace = $namespace;
}
else
{
$this->message[$pos]['namespace'] = $this->default_namespace;
}
// loop through atts, logging ns and type declarations
@reset($attrs);
while (list($key,$value) = @each($attrs))
/* foreach($attrs as $key => $value) */
{
// if ns declarations, add to class level array of valid namespaces
if(preg_match('/xmlns:/',$key))
{
$namespaces[substr(strrchr($key,':'),1)] = $value;
if($name == $this->root_struct_name)
{
$this->methodNamespace = $value;
}
}
// if it's a type declaration, set type
elseif($key == 'xsi:type')
{
// then get attname and set $type
$type = substr(strrchr($value,':'),1);
}
}
// set type if available
if($type)
{
$this->message[$pos]['type'] = $type;
}
// debug
//$this->debug("parsed $name start, eval = '".$this->message[$pos]["eval_str"]."'");
}
// end-element handler
function end_element($parser, $name)
{
// position of current element is equal to the last value left in depth_array for my depth
$pos = $this->depth_array[$this->depth];
// bring depth down a notch
$this->depth--;
// get type if not set already
if($this->message[$pos]['type'] == '')
{
// if($this->message[$pos]['cdata'] == '' && $this->message[$pos]['children'] != '')
if($this->message[$pos]['children'] != '')
{
$this->message[$pos]['type'] = 'SOAPStruct';
}
else
{
$this->message[$pos]['type'] = 'string';
}
}
// set eval str start if it has a valid type and is inside the method
if($pos >= $this->root_struct)
{
$this->message[$pos]['eval_str'] .= "\n CreateObject(\"phpgwapi.soapval\",\"".htmlspecialchars($name)."\", \"".$this->message[$pos]["type"]."\" ";
$this->message[$pos]['end_eval_str'] = ')';
$this->message[$pos]['inval'] = 'true';
/*
if($this->message[$pos]["name"] == $this->root_struct_name){
$this->message[$pos]["end_eval_str"] .= " ,\"$this->methodNamespace\"";
}
*/
if($this->message[$pos]['children'] != '')
{
$this->message[$pos]['eval_str'] .= ', array( ';
$this->message[$pos]['end_eval_str'] .= ' )';
}
}
// if i have no children and have cdata...then i must be a scalar value, so add my data to the eval_str
if($this->status == 'method' && $this->message[$pos]['children'] == '')
{
// add cdata w/ no quotes if only int/float/dbl
if($this->message[$pos]['type'] == 'string')
{
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
}
elseif($this->message[$pos]['type'] == 'int' || $this->message[$pos]['type'] == 'float' || $this->message[$pos]['type'] == 'double')
{
//$this->debug("adding cdata w/o quotes");
$this->message[$pos]['eval_str'] .= ', '.trim($this->message[$pos]['cdata']);
}
elseif(is_string($this->message[$pos]['cdata']))
{
//$this->debug("adding cdata w/ quotes");
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
}
}
// if in the process of making a soap_val, close the parentheses and move on...
if($this->message[$pos]['inval'] == 'true')
{
$this->message[$pos]['inval'] == 'false';
}
// if tag we are currently closing is the method wrapper
if($pos == $this->root_struct)
{
$this->status = 'body';
}
elseif(preg_match('/:Body/',$name))
{
$this->status = 'header';
}
elseif(preg_match('/:Header/',$name))
{
$this->status = 'envelope';
}
// set parent back to my parent
$this->parent = $this->message[$pos]['parent'];
$this->debug("parsed $name end, type '".$this->message[$pos]['type']."'eval_str = '".trim($this->message[$pos]['eval_str'])."' and children = ".$this->message[$pos]['children']);
}
// element content handler
function character_data($parser, $data)
{
$pos = $this->depth_array[$this->depth];
$this->message[$pos]['cdata'] .= $data;
//$this->debug("parsed ".$this->message[$pos]["name"]." cdata, eval = '$this->eval_str'");
}
// default handler
function default_handler($parser, $data)
{
//$this->debug("DEFAULT HANDLER: $data");
}
// function to get fault code
function fault()
{
if($this->fault)
{
return true;
}
else
{
return false;
}
}
// have this return a soap_val object
function get_response()
{
$this->debug("eval()ing eval_str: $this->eval_str");
@eval("$this->eval_str");
if($response)
{
$this->debug("successfully eval'd msg");
return $response;
}
else
{
$this->debug('ERROR: did not successfully eval the msg');
$this->fault = true;
return CreateObject('phpgwapi.soapval',
'Fault',
'struct',
array(
CreateObject('phpgwapi.soapval',
'faultcode',
'string',
'SOAP-ENV:Server'
),
CreateObject('phpgwapi.soapval',
'faultstring',
'string',
"couldn't eval \"$this->eval_str\""
)
)
);
}
}
function debug($string)
{
if($this->debug_flag)
{
$this->debug_str .= "$string\n";
}
}
function decode_entities($text)
{
@reset($this->entities);
while(list($entity,$encoded) = @each($this->entities))
/* foreach($this->entities as $entity => $encoded) */
{
$text = str_replace($encoded,$entity,$text);
}
return $text;
}
}
?>

View File

@ -1,444 +0,0 @@
<?php
// SOAP server class
// for example usage, see the test_server.php file.
class soap_server
{
function soap_server($data='',$serviceNow=False)
{
// create empty dispatch map
$this->dispatch_map = array();
$this->debug_flag = True;
$this->debug_str = '';
$this->headers = '';
$this->request = '';
$this->result = 'successful';
$this->fault = false;
$this->fault_code = '';
$this->fault_str = '';
$this->fault_actor = '';
if($serviceNow == 1)
{
$this->service($data);
}
}
// parses request and posts response
function service($data)
{
// $response is a soap_msg object
$response = get_class($data) == 'soapmsg' ? $date : $this->parseRequest($data);
$this->debug("parsed request and got an object of this class '".get_class($response)."'");
$this->debug("server sending...");
// pass along the debug string
if($this->debug_flag)
{
$response->debug($this->debug_str);
}
$payload = $response->serialize();
// print headers
if($this->fault)
{
$header[] = "HTTP/1.0 500 Internal Server Error\r\n";
}
else
{
$header[] = "HTTP/1.0 200 OK\r\n";
$header[] = "Status: 200\r\n";
}
$header[] = "Server: SOAPx4 Server v0.344359s\r\n";
$header[] = "Connection: Close\r\n";
$header[] = "Content-Type: text/xml; charset=UTF-8\r\n";
$header[] = "Content-Length: ".strlen($payload)."\r\n\r\n";
reset($header);
foreach($header as $hdr)
{
header($hdr);
}
print $payload;
}
function parseRequest($data="")
{
global $HTTP_SERVER_VARS;
$this->debug("entering parseRequest() on ".date("H:i Y-m-d"));
$request_uri = $HTTP_SERVER_VARS["REQUEST_URI"];
$this->debug("request uri: $request_uri");
// get headers
$headers_array = getallheaders();
foreach($headers_array as $k=>$v)
{
$dump .= "$k: $v\r\n";
}
$dump .= "\r\n\r\n".$data;
$this->headers = $headers_array;
$this->request = $dump;
// get SOAPAction header -> methodname
if($headers_array["SOAPAction"])
{
$action = str_replace('"','',$headers_array["SOAPAction"]);
if(preg_match('/'."^urn:".'/',$action))
{
$this->service = substr($action,4);
}
elseif(preg_match('/'.".php".'/',$action))
{
$this->service = preg_replace('/"|\\//','',substr(strrchr($action,".php"),4,strlen(strrchr($action,"/"))));
}
$this->debug("got service: $this->service");
}
else
{
// throw a fault if no soapaction
$this->debug("ERROR: no SOAPAction header found");
}
// NOTE:::: throw a fault for no/bad soapaction here?
// parse response, get soap parser obj
$parser = CreateObject('phpgwapi.soap_parser',$data);
// get/set methodname
$this->methodname = $parser->root_struct_name;
$this->debug("method name: $this->methodname");
// does method exist?
$test = preg_replace('/'."\.".'/','_',$this->methodname);
if(function_exists($test))
{
$method = $this->methodname = $test;
$this->debug("method '$this->methodname' exists");
}
else
{
/* egroupware customization - createobject based on methodname */
list($app,$class,$method) = explode('.',$this->methodname);
if(preg_match('/'."^service".'/',$app))
{
$args = $class;
$class = 'service';
$app = 'phpgwapi';
$obj = CreateObject(sprintf('%s.%s',$app,$class),$args);
unset($args);
}
else
{
$obj = CreateObject(sprintf('%s.%s',$app,$class));
}
$this->debug('app: ' . $app . ', class: ' . $class . ', method: ' . $method);
/*
// "method not found" fault here
$this->debug("method '$obj->method' not found!");
$this->result = "fault: method not found";
$this->make_fault("Server","method '$obj->method' not defined in service '$this->service'");
return $this->fault();
*/
}
// if fault occurred during message parsing
if($parser->fault())
{
// parser debug
$this->debug($parser->debug_str);
$this->result = "fault: error in msg parsing or eval";
$this->make_fault("Server","error in msg parsing or eval:\n".$parser->get_response());
// return soapresp
return $this->fault();
// else successfully parsed request into soapval object
}
else
{
// get eval_str
$this->debug("calling parser->get_response()");
// evaluate it, getting back a soapval object
if(!$request_val = $parser->get_response())
{
return $this->fault();
}
// parser debug
$this->debug($parser->debug_str);
if(get_class($request_val) == "soapval")
{
if (is_object($obj))
{
/* Add the function to the server map */
$in = "array('" . implode("','",$obj->soap_functions[$method]['in']) . "')";
$out = "array('" . implode("','",$obj->soap_functions[$method]['out']) . "')";
$evalmap = "\$this->add_to_map(\$this->methodname,$in,$out);";
eval($evalmap);
}
/* verify that soapval objects in request match the methods signature */
if($this->verify_method($request_val))
{
$this->debug("request data - name: $request_val->name, type: $request_val->type, value: $request_val->value");
if($this->input_value)
{
/* decode the soapval object, and pass resulting values to the requested method */
if(!$request_data = $request_val->decode())
{
$this->make_fault("Server","Unable to decode response from soapval object into native php type.");
return $this->fault();
}
$this->debug("request data: $request_data");
}
/* if there are return values */
if($this->return_type = $this->get_return_type())
{
$this->debug("got return type: '$this->return_type'");
/* if there are parameters to pass */
if($request_data)
{
if (is_object($obj))
{
$code = "\$method_response = call_user_func(array($obj,$method),";
$this->debug("about to call object method '$class\-\>$method' with args");
}
else
{
$code = '$method_response = ' . $this->methodname . "('";
$args = implode("','",$request_data['return']);
$this->debug("about to call method '$this->methodname' with args: $args");
}
/* call method with parameters */
$code .= implode("','",$request_data['return']);
/*
while(list($x,$y) = each($request_data))
{
$code .= "\$request_data[$x]" . ',';
}
$code = substr($code,0,-1) .");";
*/
$code .= "');";
$this->debug('CODE: ' . $code);
if(eval($code))
{
if (is_object($obj))
{
$this->make_fault("Server","Object method call failed for '$class\-\>$method' with params: ".join(',',$request_data));
}
else
{
$this->make_fault("Server","Method call failed for '$this->methodname' with params: ".join(',',$request_data));
}
return $this->fault();
}
$this->debug('Response: ' . $method_response);
// _debug_array($method_response);
}
else
{
/* call method w/ no parameters */
if (is_object($obj))
{
$this->debug("about to call object method '$obj\-\>$method'");
if(!$method_response = call_user_func(array($obj,$method)))
{
$this->make_fault("Server","Method call failed for '$obj->method' with no params");
return $this->fault();
}
}
else
{
$this->debug("about to call method '$this->methodname'");
if(!$method_response = call_user_func($this->methodname))
{
$this->make_fault("Server","Method call failed for '$this->methodname' with no params");
return $this->fault();
}
}
}
/* no return values */
}
else
{
if($request_data)
{
/* call method with parameters */
$code = "\$method_response = call_user_func(array(\$obj,\$method),";
while(list($x,$y) = each($request_data))
{
$code .= "\$request_data[$x]" . ',';
}
$code = substr($code,0,-1) .");";
$this->debug("about to call object method '$obj\-\>$method'");
eval($code);
}
else
{
/* call method w/ no parameters */
if(is_object($obj))
{
$this->debug("about to call object method '$obj\-\>$method'");
call_user_func(array($obj,$method));
}
else
{
$this->debug("about to call method '$method'");
call_user_func($method);
}
}
}
/* create soap_val object w/ return values from method, use method signature to determine type */
if(get_class($method_response) != 'soapval')
{
$return_val = CreateObject('phpgwapi.soapval',$method,$this->return_type,$method_response);
}
else
{
$return_val = $method_response;
}
$this->debug($return_val->debug_str);
/* response object is a soap_msg object */
$return_msg = CreateObject('phpgwapi.soapmsg',$method.'Response',array($return_val),$this->service);
if($this->debug_flag)
{
$return_msg->debug_flag = true;
}
$this->result = "successful";
return $return_msg;
}
else
{
// debug
$this->debug("ERROR: request not verified against method signature");
$this->result = "fault: request failed validation against method signature";
// return soapresp
return $this->fault();
}
}
else
{
// debug
$this->debug("ERROR: parser did not return soapval object: $request_val ".get_class($request_val));
$this->result = "fault: parser did not return soapval object: $request_val";
// return fault
$this->make_fault("Server","parser did not return soapval object: $request_val");
return $this->fault();
}
}
}
function verify_method($request)
{
//return true;
$this->debug("entered verify_method() w/ request name: ".$request->name);
$params = $request->value;
// if there are input parameters required...
if($sig = $this->dispatch_map[$this->methodname]["in"])
{
$this->input_value = count($sig);
if(is_array($params))
{
$this->debug("entered verify_method() with ".count($params)." parameters");
foreach($params as $v)
{
$this->debug("param '$v->name' of type '$v->type'");
}
// validate the number of parameters
if(count($params) == count($sig))
{
$this->debug("got correct number of parameters: ".count($sig));
// make array of param types
foreach($params as $param)
{
$p[] = strtolower($param->type);
}
// validate each param's type
for($i=0; $i < count($p); $i++)
{
// type not match
if(strtolower($sig[$i]) != strtolower($p[$i]))
{
$this->debug("mismatched parameter types: $sig[$i] != $p[$i]");
$this->make_fault("Client","soap request contained mismatching parameters of name $v->name had type $p[$i], which did not match signature's type: $sig[$i]");
return false;
}
$this->debug("parameter type match: $sig[$i] = $p[$i]");
}
return true;
// oops, wrong number of paramss
}
else
{
$this->debug("oops, wrong number of parameter!");
$this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' required ".count($sig)." and request provided ".count($params));
return false;
}
// oops, no params...
}
else
{
$this->debug("oops, no parameters sent! Method '$this->methodname' requires ".count($sig)." input parameters!");
$this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' requires ".count($sig)." parameters, and request provided none");
return false;
}
// no params
}
elseif( (count($params)==0) && (count($sig) <= 1) )
{
$this->input_values = 0;
return true;
}
else
{
//$this->debug("well, request passed parameters to a method that requires none?");
//$this->make_fault("Client","method '$this->methodname' requires no parameters. The request passed in ".count($params).": ".@implode(" param: ",$params) );
return true;
}
}
// get string return type from dispatch map
function get_return_type()
{
if(count($this->dispatch_map[$this->methodname]["out"]) >= 1)
{
$type = array_shift($this->dispatch_map[$this->methodname]["out"]);
$this->debug("got return type from dispatch map: '$type'");
return $type;
}
return false;
}
// dbg
function debug($string)
{
if($this->debug_flag)
{
$this->debug_str .= "$string\n";
}
}
// add a method to the dispatch map
function add_to_map($methodname,$in,$out)
{
$this->dispatch_map[$methodname]["in"] = $in;
$this->dispatch_map[$methodname]["out"] = $out;
}
// set up a fault
function fault()
{
return CreateObject('phpgwapi.soapmsg',
"Fault",
array(
"faultcode" => $this->fault_code,
"faultstring" => $this->fault_str,
"faultactor" => $this->fault_actor,
"faultdetail" => $this->fault_detail.$this->debug_str
),
"http://schemas.xmlphpgwapi.org/soap/envelope/"
);
}
function make_fault($fault_code,$fault_string)
{
$this->fault_code = $fault_code;
$this->fault_str = $fault_string;
$this->fault = true;
}
}
?>

View File

@ -1,185 +0,0 @@
<?php
/*
SOAPx4
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
This project began based on code from the 2 projects below,
and still contains some original code. The licenses of both must be respected.
XML-RPC for PHP
originally by Edd Dumbill (C) 1999-2000
SOAP for PHP
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
*/
/* changelog:
2001-07-04
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
solidification.)
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
- implemented a transport argument into send() that allows you to specify different transports
(assuming you have implemented the function, and added it to the conditional statement in send()
- abstracted the determination of charset in Content-type header
2001-07-5
- fixed more weird type/namespace issues
*/
// $path can be a complete endpoint url, with the other parameters left blank:
// $soap_client = new soap_client("http://path/to/soap/server");
/* soapx4 high level class
usage:
// instantiate client with server info
$soapclient = new soapclient( string path [ ,boolean wsdl] );
// call method, get results
echo $soapclient->call( string methodname [ ,array parameters] );
// bye bye client
unset($soapclient);
*/
/* $Id$ */
class soapclient
{
function soapclient($endpoint,$wsdl=False,$portName=False)
{
$this->debug_flag = True;
$this->endpoint = $endpoint;
$this->portName = False;
// make values
if($wsdl)
{
$this->endpointType = 'wsdl';
if($portName)
{
$this->portName = $portName;
}
}
}
function call($method,$params='',$namespace=false,$soapAction=false)
{
if($this->endpointType == 'wsdl')
{
// instantiate wsdl class
$this->wsdl = CreateObject('phpgwapi.wsdl',$this->endpoint);
// get portName
if(!$this->portName)
{
$this->portName = $this->wsdl->getPortName($method);
}
// get endpoint
if(!$this->endpoint = $this->wsdl->getEndpoint($this->portName))
{
die("no port of name '$this->portName' in the wsdl at that location!");
}
$this->debug("endpoint: $this->endpoint");
$this->debug("portName: $this->portName");
}
// get soapAction
if(!$soapAction)
{
if($this->endpointType != 'wsdl')
{
die("method call requires soapAction if wsdl is not available!");
}
if(!$soapAction = $this->wsdl->getSoapAction($this->portName,$method))
{
die("no soapAction for operation: $method!");
}
}
$this->debug("soapAction: $soapAction");
// get namespace
if(!$namespace)
{
if($this->endpointType != 'wsdl')
{
die("method call requires namespace if wsdl is not available!");
}
if(!$namespace = $this->wsdl->getNamespace($this->portName,$method))
{
die("no soapAction for operation: $method!");
}
}
$this->debug("namespace: $namespace");
// make message
$soapmsg = CreateObject('phpgwapi.soapmsg',$method,$params,$namespace);
/* _debug_array($soapmsg); */
// instantiate client
$dbg = "calling server at '$this->endpoint'...";
if($soap_client = CreateObject('phpgwapi.soap_client',$this->endpoint))
{
//$soap_client->debug_flag = true;
$this->debug($dbg.'instantiated client successfully');
$this->debug("client data:<br>server: $soap_client->server<br>path: $soap_client->path<br>port: $soap_client->port");
// send
$dbg = "sending msg w/ soapaction '$soapAction'...";
if($return = $soap_client->send($soapmsg,$soapAction))
{
$this->request = $soap_client->outgoing_payload;
$this->response = $soap_client->incoming_payload;
$this->debug($dbg . "sent message successfully and got a '$return' back");
// check for valid response
if(get_class($return) == 'soapval')
{
// fault?
if(eregi('fault',$return->name))
{
$this->debug('got fault');
$faultArray = $return->decode();
@reset($faultArray);
while(list($k,$v) = @each($faultArray))
/* foreach($faultArray as $k => $v) */
{
print "$k = $v<br>";
}
return false;
}
else
{
$returnArray = $return->decode();
if(is_array($returnArray))
{
return array_shift($returnArray);
}
else
{
$this->debug("didn't get array back from decode() for $return->name");
return false;
}
}
}
else
{
$this->debug("didn't get soapval object back from client");
return false;
}
}
else
{
$this->debug('client send/recieve error');
return false;
}
}
}
function debug($string)
{
if($this->debug_flag)
{
print $string . '<br>';
}
}
}
?>

View File

@ -1,183 +0,0 @@
<?php
/*
SOAPx4
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
This project began based on code from the 2 projects below,
and still contains some original code. The licenses of both must be respected.
XML-RPC for PHP
originally by Edd Dumbill (C) 1999-2000
SOAP for PHP
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
*/
/* changelog:
2001-07-04
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
solidification.)
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
- implemented a transport argument into send() that allows you to specify different transports
(assuming you have implemented the function, and added it to the conditional statement in send()
- abstracted the determination of charset in Content-type header
2001-07-5
- fixed more weird type/namespace issues
*/
// $path can be a complete endpoint url, with the other parameters left blank:
// $soap_client = new soap_client("http://path/to/soap/server");
/* $Id$ */
// soap message class
class soapmsg
{
// params is an array of soapval objects
function soapmsg($method,$params,$method_namespace='http://testuri.org',$new_namespaces=False)
{
// globalize method namespace
$GLOBALS['methodNamespace'] = $method_namespace;
$namespaces = $GLOBALS['namespaces'];
// make method struct
$this->value = CreateObject('phpgwapi.soapval',$method,"struct",$params,$method_namespace);
if(is_array($new_namespaces))
{
$i = count($namespaces);
@reset($new_namespaces);
while(list($null,$v) = @each($new_namespaces))
/* foreach($new_namespaces as $v) */
{
$namespaces[$v] = 'ns' . $i++;
}
$this->namespaces = $namespaces;
}
$this->payload = '';
$this->debug_flag = True;
$this->debug_str = "entering soapmsg() with soapval ".$this->value->name."\n";
}
function make_envelope($payload)
{
$namespaces = $GLOBALS['namespaces'];
@reset($namespaces);
while(list($k,$v) = @each($namespaces))
/* foreach($namespaces as $k => $v) */
{
$ns_string .= " xmlns:$v=\"$k\"";
}
return "<SOAP-ENV:Envelope $ns_string SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
. $payload . "</SOAP-ENV:Envelope>\n";
}
function make_body($payload)
{
return "<SOAP-ENV:Body>\n" . $payload . "</SOAP-ENV:Body>\n";
}
function createPayload()
{
$value = $this->value;
$payload = $this->make_envelope($this->make_body($value->serialize()));
$this->debug($value->debug_str);
$payload = "<?xml version=\"1.0\"?>\n".$payload;
if($this->debug_flag)
{
$payload .= $this->serializeDebug();
}
$this->payload = str_replace("\n","\r\n", $payload);
}
function serialize()
{
if($this->payload == '')
{
$this->createPayload();
return $this->payload;
}
else
{
return $this->payload;
}
}
// returns a soapval object
function parseResponse($data)
{
$this->debug("Entering parseResponse()");
//$this->debug(" w/ data $data");
// strip headers here
//$clean_data = preg_replace('/'."\r\n".'/',"\n", $data);
if(preg_match('/'."^.*\r\n\r\n<".'/',$data))
{
$this->debug("found proper seperation of headers and document");
$this->debug("getting rid of headers, stringlen: ".strlen($data));
$clean_data = preg_replace('/'."^.*\r\n\r\n<".'/',"<", $data);
$this->debug("cleaned data, stringlen: ".strlen($clean_data));
}
else
{
// return fault
return CreateObject('phpgwapi.soapval',
'fault',
'SOAPStruct',
Array(
CreateObject('phpgwapi.soapval','faultcode','string','SOAP-MSG'),
CreateObject('phpgwapi.soapval','faultstring','string','HTTP Error'),
CreateObject('phpgwapi.soapval','faultdetail','string','HTTP headers were not immediately followed by \'\r\n\r\n\'')
)
);
}
/*
// if response is a proper http response, and is not a 200
if(preg_match('/'."^HTTP".'/',$clean_data) && !preg_match('/'."200$".'/', $clean_data))
{
// get error data
$errstr = substr($clean_data, 0, strpos($clean_data, "\n")-1);
// return fault
return CreateObject('phpgwapi.soapval',
"fault",
"SOAPStruct",
array(
CreateObject('phpgwapi.soapval',"faultcode","string","SOAP-MSG"),
CreateObject('phpgwapi.soapval',"faultstring","string","HTTP error")
)
);
}
*/
$this->debug("about to create parser instance w/ data: $clean_data");
// parse response
$response = CreateObject('phpgwapi.soap_parser',$clean_data);
// return array of parameters
$ret = $response->get_response();
$this->debug($response->debug_str);
return $ret;
}
// dbg
function debug($string)
{
if($this->debug_flag)
{
$this->debug_str .= "$string\n";
}
}
// preps debug data for encoding into soapmsg
function serializeDebug()
{
if($this->debug_flag)
{
return "<!-- DEBUG INFO:\n".$this->debug_str."-->\n";
}
else
{
return '';
}
}
}
?>

View File

@ -1,468 +0,0 @@
<?php
/*
SOAPx4
by Dietrich Ayala (C) 2001 dietrich@ganx4.com
This project began based on code from the 2 projects below,
and still contains some original code. The licenses of both must be respected.
XML-RPC for PHP
originally by Edd Dumbill (C) 1999-2000
SOAP for PHP
by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn>
*/
/* changelog:
2001-07-04
- abstract type system to support either 1999 or 2001 schema (arg, typing still needs much
solidification.)
- implemented proxy support, based on sample code from miles lott <milos@speakeasy.net>
- much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code
- implemented a transport argument into send() that allows you to specify different transports
(assuming you have implemented the function, and added it to the conditional statement in send()
- abstracted the determination of charset in Content-type header
2001-07-5
- fixed more weird type/namespace issues
*/
// $path can be a complete endpoint url, with the other parameters left blank:
// $soap_client = new soap_client("http://path/to/soap/server");
/* $Id$ */
// soap value object
class soapval
{
// function soapval($name='',$type=False,$value=-1,$namespace=False,$type_namespace=False)
function soapval($name='',$type=False,$value=0,$namespace=False,$type_namespace=False)
{
// detect type if not passed
if(!$type)
{
if(is_array($value) && count($value) >= 1)
{
if(ereg("[a-zA-Z0-9\-]*",key($v)))
{
$type = 'struct';
}
else
{
$type = 'array';
}
}
elseif(is_int($v))
{
$type = 'int';
}
elseif(is_float($v) || $v == 'NaN' || $v == 'INF')
{
$type = 'float';
}
else
{
$type = gettype($value);
}
}
// php type name mangle
if($type == 'integer')
{
$type = 'int';
}
$this->soapTypes = $GLOBALS['soapTypes'];
$this->name = $name;
$this->value = '';
$this->type = $type;
$this->type_code = 0;
$this->type_prefix = false;
$this->array_type = '';
$this->debug_flag = False;
$this->debug_str = '';
$this->debug("Entering soapval - name: '$name' type: '$type'");
if($namespace)
{
$this->namespace = $namespace;
if(!isset($GLOBALS['namespaces'][$namespace]))
{
$GLOBALS['namespaces'][$namespace] = "ns".(count($GLOBALS['namespaces'])+1);
}
$this->prefix = $GLOBALS['namespaces'][$namespace];
}
// get type prefix
if(preg_match('/'.":".'/',$type))
{
$this->type = substr(strrchr($type,':'),1,strlen(strrchr($type,':')));
$this->type_prefix = substr($type,0,strpos($type,':'));
}
elseif($type_namespace)
{
if(!isset($GLOBALS['namespaces'][$type_namespace]))
{
$GLOBALS['namespaces'][$type_namespace] = 'ns'.(count($GLOBALS['namespaces'])+1);
}
$this->type_prefix = $GLOBALS['namespaces'][$type_namespace];
}
// if type namespace was not explicitly passed, and we're not in a method struct:
elseif(!$this->type_prefix && !isset($this->namespace))
{
// try to get type prefix from typeMap
if(!$this->type_prefix = $this->verify_type($type))
{
// else default to method namespace
$this->type_prefix = $GLOBALS['namespaces'][$GLOBALS['methodNamespace']];
}
}
// if scalar
if($this->soapTypes[$this->type] == 1)
{
$this->type_code = 1;
$this->addScalar($value,$this->type,$name);
// if array
}
elseif($this->soapTypes[$this->type] == 2)
{
$this->type_code = 2;
$this->addArray($value);
// if struct
}
elseif($this->soapTypes[$this->type] == 3)
{
$this->type_code = 3;
$this->addStruct($value);
}
else
{
//if($namespace == $GLOBALS['methodNamespace']){
$this->type_code = 3;
$this->addStruct($value);
//}
}
}
function addScalar($value, $type, $name="")
{
$this->debug("adding scalar '$name' of type '$type'");
// if boolean, change value to 1 or 0
if ($type == "boolean")
{
if((strcasecmp($value,"true") == 0) || ($value == 1))
{
$value = 1;
}
else
{
$value = 0;
}
}
$this->value = $value;
return true;
}
function addArray($vals)
{
$this->debug("adding array '$this->name' with ".count($vals)." vals");
$this->value = array();
if(is_array($vals) && count($vals) >= 1)
{
@reset($vals);
while(list($k,$v) = @each($vals))
/* foreach($vals as $k => $v) */
{
$this->debug("checking value $k : $v");
// if soapval, add..
if(get_class($v) == 'soapval')
{
$this->value[] = $v;
$this->debug($v->debug_str);
// else make obj and serialize
}
else
{
if(is_array($v))
{
if(ereg("[a-zA-Z\-]*",key($v)))
{
$type = 'struct';
}
else
{
$type = 'array';
}
}
elseif(!preg_match('/'."^[0-9]*$".'/',$k) && in_array($k,array_keys($this->soapTypes)))
{
$type = $k;
}
elseif(is_int($v))
{
$type = 'int';
}
elseif(is_float($v) || $v == 'NaN' || $v == 'INF')
{
$type = 'float';
}
else
{
$type = gettype($v);
}
$new_val = CreateObject('phpgwapi.soapval','item',$type,$v);
$this->debug($new_val->debug_str);
$this->value[] = $new_val;
}
}
}
return true;
}
function addStruct($vals)
{
$this->debug("adding struct '$this->name' with ".count($vals).' vals');
if(is_array($vals) && count($vals) >= 1)
{
@reset($vals);
while(list($k,$v) = @each($vals))
/* foreach($vals as $k => $v) */
{
// if serialize, if soapval
if(get_class($v) == 'soapval')
{
$this->value[] = $v;
$this->debug($v->debug_str);
// else make obj and serialize
}
else
{
if(is_array($v))
{
@reset($v);
while(list($a,$b) = @each($v))
/* foreach($v as $a => $b) */
{
if($a == "0")
{
$type = 'array';
}
else
{
$type = 'struct';
}
break;
}
}
// elseif(is_array($k) && in_array($k,array_keys($this->soapTypes)))
elseif(is_array($k,in_array($k,array_keys($this->soapTypes))))
{
$this->debug("got type '$type' for value '$v' from soapTypes array!");
$type = $k;
}
elseif(is_int($v))
{
$type = 'int';
}
elseif(is_float($v) || $v == "NaN" || $v == "INF")
{
$type = 'float';
}
else
{
$type = gettype($v);
$this->debug("got type '$type' for value '$v' from php gettype()!");
}
$new_val = CreateObject('phpgwapi.soapval',$k,$type,$v);
$this->debug($new_val->debug_str);
$this->value[] = $new_val;
}
}
}
else
{
$this->value = array();
}
return true;
}
// turn soapvals into xml, woohoo!
function serializeval($soapval=false)
{
if(!$soapval)
{
$soapval = $this;
}
$this->debug("serializing '$soapval->name' of type '$soapval->type'");
if($soapval->name == '')
{
$soapval->name = 'return';
}
switch($soapval->type_code)
{
case 3:
// struct
$this->debug('got a struct');
if($soapval->prefix && $soapval->type_prefix)
{
$xml .= "<$soapval->prefix:$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n";
}
elseif($soapval->type_prefix)
{
$xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n";
}
elseif($soapval->prefix)
{
$xml .= "<$soapval->prefix:$soapval->name>\n";
}
else
{
$xml .= "<$soapval->name>\n";
}
if(is_array($soapval->value))
{
@reset($soapval->value);
while(list($k,$v) = @each($soapval->value))
/* foreach($soapval->value as $k => $v) */
{
$xml .= $this->serializeval($v);
}
}
if($soapval->prefix)
{
$xml .= "</$soapval->prefix:$soapval->name>\n";
}
else
{
$xml .= "</$soapval->name>\n";
}
break;
case 2:
// array
@reset($soapval->value);
while(list($null,$array_val) = @each($soapval->value))
/* foreach($soapval->value as $array_val) */
{
$array_types[$array_val->type] = 1;
$xml .= $this->serializeval($array_val);
}
if(count($array_types) > 1)
{
$array_type = 'xsd:ur-type';
}
elseif(count($array_types) >= 1)
{
$array_type = $array_val->type_prefix.":".$array_val->type;
}
$xml = "<$soapval->name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_type."[".sizeof($soapval->value)."]\">\n".$xml."</$soapval->name>\n";
break;
case 1:
$xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">$soapval->value</$soapval->name>\n";
break;
default:
break;
}
return $xml;
}
// serialize
function serialize()
{
return $this->serializeval($this);
}
function decode($soapval=false)
{
if(!$soapval)
{
$soapval = $this;
}
// scalar decode
if($soapval->type_code == 1)
{
return $soapval->value;
// array decode
}
elseif($soapval->type_code == 2)
{
if(is_array($soapval->value))
{
@reset($soapval->value);
while(list($null,$item) = @each($soapval->value))
/* foreach($soapval->value as $item) */
{
$return[] = $this->decode($item);
}
return $return;
}
else
{
return array();
}
// struct decode
}
elseif($soapval->type_code == 3)
{
if(is_array($soapval->value))
{
@reset($soapval->value);
while(list($null,$item) = @each($soapval->value))
/* foreach($soapval->value as $item) */
{
$return[$item->name] = $this->decode($item);
}
return $return;
}
else
{
return array();
}
}
}
// verify type
function verify_type($type)
{
if ($type)
{
// global $GLOBALS['namespaces'],$GLOBALS['soapTypes'],$GLOBALS['typemap'];
// global $GLOBALS['namespaces'],$GLOBALS['typemap'];
@reset($GLOBALS['typemap']);
while(list($namespace,$types) = @each($GLOBALS['typemap']))
/* foreach($GLOBALS['typemap'] as $namespace => $types) */
{
if(in_array($type,$types))
{
return $GLOBALS['namespaces'][$namespace];
}
}
}
return false;
}
// alias for verify_type() - pass it a type, and it returns it's prefix
function get_prefix($type)
{
if($prefix = $this->verify_type($type))
{
return $prefix;
}
return false;
}
function debug($string)
{
if($this->debug_flag)
{
$this->debug_str .= "$string\n";
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,742 +0,0 @@
<?php
// Copyright (c) 1999,2000,2001 Edd Dumbill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of the "XML-RPC for PHP" nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
/* $Id$ */
class xmlrpc_client
{
var $path;
var $server;
var $port=0;
var $method='http';
var $errno;
var $errstr;
var $debug=0;
var $username='';
var $password='';
var $cert='';
var $certpass='';
var $verifypeer=1;
var $verifyhost=1;
var $no_multicall=False;
var $proxy = '';
var $proxyport=0;
var $proxy_user = '';
var $proxy_pass = '';
/**
* List of http compression methods accepted by the client for responses.
* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
*
* NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
* in those cases it will be up to CURL to decide the compression methods
* it supports. You might check for the presence of 'zlib' in the output of
* curl_version() to determine wheter compression is supported or not
*/
var $accepted_compression = array();
/**
* Name of compression scheme to be used for sending requests.
* Either null, gzip or deflate
*/
var $request_compression = '';
/**
* CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
* http://curl.haxx.se/docs/faq.html#7.3)
*/
var $xmlrpc_curl_handle = null;
/// Whether to use persistent connections for http 1.1 and https
var $keepalive = false;
function xmlrpc_client($path, $server='', $port='', $method='')
{
// allow user to specify all params in $path
if($server == '' and $port == '' and $method == '')
{
$parts = parse_url($path);
$server = $parts['host'];
$path = $parts['path'];
if(isset($parts['query']))
{
$path .= '?'.$parts['query'];
}
if(isset($parts['fragment']))
{
$path .= '#'.$parts['fragment'];
}
if(isset($parts['port']))
{
$port = $parts['port'];
}
if(isset($parts['scheme']))
{
$method = $parts['scheme'];
}
if(isset($parts['user']))
{
$this->username = $parts['user'];
}
if(isset($parts['pass']))
{
$this->password = $parts['pass'];
}
}
if($path == '' || $path[0] != '/')
{
$this->path='/'.$path;
}
else
{
$this->path=$path;
}
$this->server=$server;
if($port != '')
{
$this->port=$port;
}
if($method != '')
{
$this->method=$method;
}
// if ZLIB is enabled, let the server by default accept compressed requests
if(function_exists('gzinflate') || (
function_exists('curl_init') && (($info = curl_version()) &&
((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
))
{
$this->accepted_compression = array('gzip', 'deflate');
}
// keepalives: enabled by default ONLY for PHP >= 4.3.8
// (see http://curl.haxx.se/docs/faq.html#7.3)
if(version_compare(phpversion(), '4.3.8') >= 0)
{
$this->keepalive = true;
}
}
function setDebug($in)
{
if ($in)
{
$this->debug = 1;
}
else
{
$this->debug = 0;
}
}
function setCredentials($u, $p)
{
$this->username=$u;
$this->password=$p;
}
function setCertificate($cert, $certpass)
{
$this->cert = $cert;
$this->certpass = $certpass;
}
function setSSLVerifyPeer($i)
{
$this->verifypeer = $i;
}
function setSSLVerifyHost($i)
{
$this->verifyhost = $i;
}
/**
* set proxy info
*
* @param string $proxyhost
* @param string $proxyport. Defaults to 8080 for HTTP and 443 for HTTPS
* @param string $proxyusername
* @param string $proxypassword
* @access public
*/
function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
{
$this->proxy = $proxyhost;
$this->proxyport = $proxyport;
$this->proxy_user = $proxyusername;
$this->proxy_pass = $proxypassword;
}
function& send($msg, $timeout=0, $method='')
{
// if user does not specify http protocol, use native method of this client
// (i.e. method set during call to constructor)
if($method == '')
{
$method = $this->method;
}
if(is_array($msg))
{
// $msg is an array of xmlrpcmsg's
$r =& $this->multicall($msg, $timeout, $method);
return $r;
}
elseif(is_string($msg))
{
$n = new xmlrpcmsg('');
$n->payload = $msg;
$msg = $n;
}
// where msg is an xmlrpcmsg
$msg->debug=$this->debug;
switch($method)
{
case 'https':
$r =& $this->sendPayloadHTTPS(
$msg,
$this->server,
$this->port,
$timeout,
$this->username,
$this->password,
$this->cert,
$this->certpass,
$this->proxy,
$this->proxyport,
$this->proxy_user,
$this->proxy_pass,
'https',
$this->keepalive
);
break;
case 'http11':
$r =& $this->sendPayloadCURL(
$msg,
$this->server,
$this->port,
$timeout,
$this->username,
$this->password,
null,
null,
$this->proxy,
$this->proxyport,
$this->proxy_user,
$this->proxy_pass,
'http',
$this->keepalive
);
break;
case 'http10':
default:
$r =& $this->sendPayloadHTTP10(
$msg,
$this->server,
$this->port,
$timeout,
$this->username,
$this->password,
$this->proxy,
$this->proxyport,
$this->proxy_user,
$this->proxy_pass
);
}
return $r;
}
function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='',
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='')
{
if($port==0)
{
$port=80;
}
// Only create the payload if it was not created previously
if(empty($msg->payload))
{
$msg->createPayload();
}
// Deflate request body and set appropriate request headers
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
{
if($this->request_compression == 'gzip')
{
$a = @gzencode($msg->payload);
if($a)
{
$msg->payload = $a;
$encoding_hdr = "Content-Encoding: gzip\r\n";
}
}
else
{
$a = @gzdeflate($msg->payload);
if($a)
{
$msg->payload = $a;
$encoding_hdr = "Content-Encoding: deflate\r\n";
}
}
}
else
{
$encoding_hdr = '';
}
// thanks to Grant Rauscher <grant7@firstworld.net>
// for this
$credentials='';
if($username!='')
{
$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
}
$accepted_encoding = '';
if(is_array($this->accepted_compression) && count($this->accepted_compression))
{
$accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
}
$proxy_credentials = '';
if($proxyhost)
{
if($proxyport == 0)
{
$proxyport = 8080;
}
$connectserver = $proxyhost;
$connectport = $proxyport;
$uri = 'http://'.$server.':'.$port.$this->path;
if($proxyusername != '')
{
$proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
}
}
else
{
$connectserver = $server;
$connectport = $port;
$uri = $this->path;
}
$op= "POST " . $uri. " HTTP/1.0\r\n"
. "User-Agent: " . $GLOBALS['xmlrpcName'] . " " . $GLOBALS['xmlrpcVersion'] . "\r\n"
. 'X-EGW-Server: ' . $this->server . ' ' . "\r\n"
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
. "Host: ". $this->server . "\r\n"
. $credentials
. $proxy_credentials
. $accepted_encoding
. $encoding_hdr
. "Accept-Charset: " . $GLOBALS['xmlrpc_defencoding'] . "\r\n"
. "Content-Type: text/xml\r\nContent-Length: "
. strlen($msg->payload) . "\r\n\r\n"
. $msg->payload;
if($timeout>0)
{
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
}
else
{
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
}
if($fp)
{
if($timeout>0 && function_exists('stream_set_timeout'))
{
stream_set_timeout($fp, $timeout);
}
}
else
{
$this->errstr='Connect error: '.$this->errstr;
$r = CreateObject(
'phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['http_error'],
$GLOBALS['xmlrpcstr']['http_error']
);
return $r;
}
if(!fputs($fp, $op, strlen($op)))
{
$this->errstr = 'Write error';
return CreateObject(
'phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['http_error'],
$GLOBALS['xmlrpcstr']['http_error']
);
}
else
{
// should we reset errno and errstr on succesful socket connection?
}
$resp =& $msg->parseResponseFile($fp);
// shall we move this into parseresponsefile, cuz' we have to close the socket 1st
// and do the parsing second if we want to have recursive calls
// (i.e. redirects)
fclose($fp);
return $resp;
}
// contributed by Justin Miller <justin@voxel.net>
// requires curl to be built into PHP
// NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
function &sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='',
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $keepalive=false)
{
$r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, $password, $cert, $certpass,
$proxyhost, $proxyport, $proxyusername, $proxypassword, $keepalive);
return $r;
}
function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', $password='', $cert='', $certpass='',
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $method='https', $keepalive=false)
{
if(!function_exists('curl_init'))
{
$r = CreateObject(
'phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['no_curl'],
$GLOBALS['xmlrpcstr']['no_curl']
);
return $r;
}
if($method == 'https')
{
if(($info = curl_version()) &&
((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
{
$this->errstr = 'SSL unavailable on this install';
$r = CreateObject(
'phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['no_ssl'],
$GLOBALS['xmlrpcstr']['no_ssl']
);
return $r;
}
}
if($port == 0)
{
if($method == 'http')
{
$port = 80;
}
else
{
$port = 443;
}
}
// Only create the payload if it was not created previously
if(empty($msg->payload))
{
$msg->createPayload();
}
// Deflate request body and set appropriate request headers
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
{
if($this->request_compression == 'gzip')
{
$a = @gzencode($msg->payload);
if($a)
{
$msg->payload = $a;
$encoding_hdr = "Content-Encoding: gzip";
}
}
else
{
$a = @gzdeflate($msg->payload);
if($a)
{
$msg->payload = $a;
$encoding_hdr = "Content-Encoding: deflate";
}
}
}
else
{
$encoding_hdr = '';
}
if(!$keepalive || !$this->xmlrpc_curl_handle)
{
$curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
if($keepalive)
{
$this->xmlrpc_curl_handle = $curl;
}
}
else
{
$curl = $this->xmlrpc_curl_handle;
}
// results into variable
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
if($this->debug)
{
curl_setopt($curl, CURLOPT_VERBOSE, 1);
}
curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']);
// required for XMLRPC: post the data
curl_setopt($curl, CURLOPT_POST, 1);
// the data
curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
// return the header too
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'X-EGW-Server: ' . $this->server,
'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'],
'Content-Type: text/xml'
));
// will only work with PHP >= 5.0
// NB: if we set an empty string, CURL will add http header indicating
// ALL methods it is supporting. This is possibly a better option than
// letting the user tell what curl can / cannot do...
if(is_array($this->accepted_compression) && count($this->accepted_compression))
{
//curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
curl_setopt($curl, CURLOPT_ENCODING, '');
}
// extra headers
$headers = array('Content-Type: text/xml', 'Accept-Charset: '.$GLOBALS['xmlrpc_internalencoding']);
// if no keepalive is wanted, let the server know it in advance
if(!$keepalive)
{
$headers[] = 'Connection: close';
}
// request compression header
if($encoding_hdr)
{
$headers[] = $encoding_hdr;
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
// timeout is borked
if($timeout)
{
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
}
if($username && $password)
{
curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
}
if($method == 'https')
{
// set cert file
if($cert)
{
curl_setopt($curl, CURLOPT_SSLCERT, $cert);
}
// set cert password
if($certpass)
{
curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
}
// whether to verify remote host's cert
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
// whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
}
// proxy info
if($proxyhost)
{
if($proxyport == 0)
{
$proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
}
curl_setopt($curl, CURLOPT_PROXY,$proxyhost.':'.$proxyport);
//curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
if($proxyusername)
{
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
}
}
$result = curl_exec($curl);
if(!$result)
{
$this->errstr = 'Write error';
$resp = CreateObject(
'phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['curl_fail'],
$GLOBALS['xmlrpcstr']['curl_fail'] . ': ' . curl_error($curl)
);
if(!$keepalive)
{
curl_close($curl);
}
}
else
{
if(!$keepalive)
{
curl_close($curl);
}
$resp =& $msg->parseResponse($result, true);
}
return $resp;
}
function& multicall($msgs, $timeout=0, $method='http')
{
$results = false;
if(!$this->no_multicall)
{
$results = $this->_try_multicall($msgs, $timeout, $method);
if($results !== false)
{
// Either the system.multicall succeeded, or the send
// failed (e.g. due to HTTP timeout). In either case,
// we're done for now.
return $results;
}
else
{
// system.multicall unsupported by server,
// don't try it next time...
$this->no_multicall = true;
}
}
// system.multicall is unupported by server:
// Emulate multicall via multiple requests
$results = array();
foreach($msgs as $msg)
{
$results[] =& $this->send($msg, $timeout, $method);
}
return $results;
}
// Attempt to boxcar $msgs via system.multicall.
function _try_multicall($msgs, $timeout, $method)
{
// Construct multicall message
$calls = array();
foreach($msgs as $msg)
{
$call['methodName'] = new xmlrpcval($msg->method(),'string');
$numParams = $msg->getNumParams();
$params = array();
for($i = 0; $i < $numParams; $i++)
{
$params[$i] = $msg->getParam($i);
}
$call['params'] = new xmlrpcval($params, 'array');
$calls[] = new xmlrpcval($call, 'struct');
}
$multicall = new xmlrpcmsg('system.multicall');
$multicall->addParam(new xmlrpcval($calls, 'array'));
// Attempt RPC call
$result =& $this->send($multicall, $timeout, $method);
//if(!is_object($result))
//{
// return ($result || 0); // transport failed
//}
if($result->faultCode() != 0)
{
return false; // system.multicall failed
}
// Unpack responses.
$rets = $result->value();
if($rets->kindOf() != 'array')
{
return false; // bad return type from system.multicall
}
$numRets = $rets->arraysize();
if($numRets != count($msgs))
{
return false; // wrong number of return values.
}
$response = array();
for($i = 0; $i < $numRets; $i++)
{
$val = $rets->arraymem($i);
switch($val->kindOf())
{
case 'array':
if($val->arraysize() != 1)
{
return false; // Bad value
}
// Normal return value
$response[$i] = new xmlrpcresp($val->arraymem(0));
break;
case 'struct':
$code = $val->structmem('faultCode');
if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
{
return false;
}
$str = $val->structmem('faultString');
if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
{
return false;
}
$response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
break;
default:
return false;
}
}
return $response;
}
} // end class xmlrpc_client
?>

View File

@ -1,177 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare API - XML-RPC Server *
* ------------------------------------------------------------------------ *
* This library is part of the eGroupWare API *
* http://www.egroupware.org/api *
* ------------------------------------------------------------------------ *
* This library 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.1 of the License, *
* or any later version. *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* You should have received a copy of the GNU Lesser 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 *
\**************************************************************************/
/* $Id$ */
// contains useful functions for xmlrpc methods
class xmlrpc_server_shared
{
var $simpledate = False;
// convert a date-array or timestamp into a datetime.iso8601 string
function date2iso8601($date)
{
if (!is_array($date))
{
if($this->simpledate)
{
return date('Ymd\TH:i:s',$date);
}
return date('Y-m-d\TH:i:s',$date);
}
$formatstring = "%04d-%02d-%02dT%02d:%02d:%02d";
if($this->simpledate)
{
$formatstring = "%04d%02d%02dT%02d:%02d:%02d";
}
return sprintf($formatstring,
$date['year'],$date['month'],$date['mday'],
$date['hour'],$date['min'],$date['sec']);
}
// convert a datetime.iso8601 string into a datearray or timestamp
function iso86012date($isodate,$timestamp=False)
{
$arr = array();
if (preg_match('/^([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})$/',$isodate,$arr))
{
// $isodate is simple ISO8601, remove the difference between split and ereg
array_shift($arr);
}
elseif (($arr = preg_split('/[-:T]/',$isodate)) && count($arr) == 6)
{
// $isodate is extended ISO8601, do nothing
}
else
{
return False;
}
foreach(array('year','month','mday','hour','min','sec') as $n => $name)
{
$date[$name] = (int)$arr[$n];
}
return $timestamp ? mktime($date['hour'],$date['min'],$date['sec'],
$date['month'],$date['mday'],$date['year']) : $date;
}
// translate cat-ids to array with id-name pairs
function cats2xmlrpc($cats)
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
}
$xcats = array();
foreach($cats as $cat)
{
if ($cat)
{
$xcats[$cat] = stripslashes($GLOBALS['egw']->categories->id2name($cat));
}
}
return $xcats;
}
// translate cats back to cat-ids, creating / modifying cats on the fly
function xmlrpc2cats($xcats)
{
if (!is_array($xcats))
{
$xcats = array();
}
elseif (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
}
$cats = array();
foreach($xcats as $cat => $name)
{
if ($id = $GLOBALS['egw']->categories->name2id($name))
{
// existing cat-name use the id
$cat = $id;
}
elseif (!($org_name = stripslashes($GLOBALS['egw']->categories->id2name($cat))) || $org_name == '--')
{
// new cat
$cat = $GLOBALS['egw']->categories->add(array('name' => $name,'parent' => 0));
}
elseif ($org_name != $name)
{
// cat-name edited
list($cat_vals) =$GLOBALS['egw']->categories->return_single($cat);
$cat_vals['name'] = $name;
$GLOBALS['egw']->categories->edit($cat_vals);
}
$cats[] = (int)$cat;
}
return $cats;
}
// get list (array with id-name pairs) of all cats of $app
function categories($complete = False,$app = '')
{
if (is_array($complete))
{
$complete = @$complete[0];
}
if (!$app)
{
list($app) = explode('.',$this->last_method);
}
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories = CreateObject('phpgwapi.categories');
}
if ($GLOBALS['egw']->categories->app_name != $app)
{
$GLOBALS['egw']->categories->categories('',$app);
}
$cats_arr = $GLOBALS['egw']->categories->return_sorted_array(0,False,'','','',True);
$cats = array();
if (is_array($cats_arr))
{
foreach($cats_arr as $cat)
{
foreach(array('name','description') as $name)
{
$cat[$name] = stripslashes($cat[$name]);
}
$cats[$cat['id']] = $complete ? $cat : $cat['name'];
}
}
return $cats;
}
function setSimpleDate($enable=True)
{
$this->simpledate = $enable;
}
}
if(empty($GLOBALS['egw_info']['server']['xmlrpc_type']))
{
$GLOBALS['egw_info']['server']['xmlrpc_type'] = 'php';
}
include_once(EGW_API_INC.SEP.'class.xmlrpc_server_' . $GLOBALS['egw_info']['server']['xmlrpc_type'] . '.inc.php');

View File

@ -1,335 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare API - XML-RPC Server *
* This file written by Miles Lott <milos@groupwhere.org> *
* Copyright (C) 2003 Miles Lott *
* -------------------------------------------------------------------------*
* This library 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.1 of the License, *
* or any later version. *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* You should have received a copy of the GNU Lesser 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 *
\**************************************************************************/
/* $Id$ */
class xmlrpc_server extends xmlrpc_server_shared
{
var $server = '';
var $authed = True;
var $log = False; //'/tmp/xmlrpc.log';
var $last_method = '';
function xmlrpc_server($dispMap='', $serviceNow=0)
{
$this->server = xmlrpc_server_create();
if($dispMap)
{
$this->dmap = $dispMap;
if($serviceNow)
{
$this->service();
}
}
}
function serializeDebug()
{
}
function service($r = False)
{
if (!$r) // do we have a response, or we need to parse the request
{
$r = $this->parseRequest();
}
if(!$r)
{
header('WWW-Authenticate: Basic realm="eGroupWare xmlrpc"');
header('HTTP/1.0 401 Unauthorized');
// for the log:
$payload = "WWW-Authenticate: Basic realm=\"eGroupWare xmlrpc\"\nHTTP/1.0 401 Unauthorized\n";
echo $payload;
}
else
{
// $payload = '<?xml version="1.0"?\>' . "\n" . $this->serializeDebug() . $r->serialize();
// Header("Content-type: text/xml\r\nContent-length: " . bytes($payload));
// print $payload;
echo $r;
}
if($this->log)
{
$fp = fopen($this->log,'a+');
fwrite($fp,"\n\n" . date('Y-m-d H:i:s') . " authorized="
. ($this->authed ? $GLOBALS['egw_info']['user']['account_lid'] : 'False')
. ", method='$this->last_method'\n");
fwrite($fp,"==== GOT ============================\n" . $GLOBALS['HTTP_RAW_POST_DATA']
. "\n==== RETURNED =======================\n");
fputs($fp,$payload);
fclose($fp);
}
if($this->debug)
{
$this->echoInput();
$fp = fopen('/tmp/xmlrpc_debug.out','a+');
fputs($fp,$payload);
fclose($fp);
}
}
function add_to_map($methodname,$function,$sig,$doc)
{
xmlrpc_server_register_method($this->server,$methodname,$function);
// xmlrpc_server_register_method($this->server,$methodname,'xmlrpc_call_wrapper');
// $descr = array(
// 'function' => $function,
// 'signature' => $sig,
// 'docstring' => $doc
// );
// xmlrpc_server_set_method_description($this->server,$methodname,$descr);
$this->dmap[$methodname] = array(
'function' => $function,
'signature' => $sig,
'docstring' => $doc
);
}
function verifySignature($in, $sig)
{
return array(1);
for($i=0; $i<sizeof($sig); $i++)
{
// check each possible signature in turn
$cursig = $sig[$i];
if (sizeof($cursig) == $in->getNumParams()+1)
{
$itsOK = 1;
for($n=0; $n<$in->getNumParams(); $n++)
{
$p = $in->getParam($n);
// print "<!-- $p -->\n";
if ($p->kindOf() == 'scalar')
{
$pt = $p->scalartyp();
}
else
{
$pt = $p->kindOf();
}
// $n+1 as first type of sig is return type
if ($pt != $cursig[$n+1])
{
$itsOK = 0;
$pno = $n+1;
$wanted = $cursig[$n+1];
$got = $pt;
break;
}
}
if ($itsOK)
{
return array(1);
}
}
}
return array(0, "Wanted $wanted, got $got at param $pno)");
}
function parseRequest($data='')
{
if($data == '')
{
$data = $GLOBALS['HTTP_RAW_POST_DATA'];
}
// return $this->echoInput($data);
/* Decode to extract methodName */
$params = xmlrpc_decode_request($data, &$methName);
$this->last_method = $methName;
$syscall = 0;
/* Setup dispatch map based on the function, if this is a system call */
if(preg_match('/^system\./', $methName))
{
foreach($GLOBALS['_xmlrpcs_dmap'] as $meth => $dat)
{
$this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']);
}
$sysCall = 1;
$dmap = $this->dmap;
}
elseif(preg_match('/^examples\./',$methName) ||
preg_match('/^validator1\./',$methName) ||
ereg('^interopEchoTests\.', $methName)
)
{
$dmap = $this->dmap;
$sysCall = 1;
}
/* verify dispatch map, or try to fix it for non-trivial system calls */
if(!isset($this->dmap[$methName]['function']))
{
if($sysCall)
{
/* Bad or non-existent system call, return error */
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['unknown_method'],
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
);
return $r;
}
if($this->authed)
{
$method = $methName;
list($app,$class,$method) = explode('.',$methName);
switch($app)
{
case 'server':
case 'phpgwapi':
/* Server role functions only - api access */
if($GLOBALS['egw']->acl->get_role() >= EGW_ACL_SERVER)
{
$dmap = ExecMethod(sprintf('%s.%s.%s','phpgwapi',$class,'list_methods'),'xmlrpc');
}
break;
case 'service':
/* Service functions, user-level */
$t = 'phpgwapi.' . $class . '.exec';
$dmap = ExecMethod($t,array($service,'list_methods','xmlrpc'));
break;
default:
/* User-level application access */
if($GLOBALS['egw']->acl->check('run',EGW_ACL_READ,$app))
{
$dmap = ExecMethod(sprintf('',$app,$class,'list_methods'),'xmlrpc');
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['no_access'],
$GLOBALS['xmlrpcstr']['no_access']
);
return $r;
}
}
}
}
/* add the functions from preset $dmap OR list_methods() to the server map */
foreach($dmap as $meth => $dat)
{
$this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']);
}
/* _debug_array($this->dmap);exit; */
/* Now make the call */
if(isset($dmap[$methName]['function']))
{
// dispatch if exists
if(isset($dmap[$methName]['signature']))
{
$sr = $this->verifySignature($m, $dmap[$methName]['signature'] );
}
if((!isset($dmap[$methName]['signature'])) || $sr[0])
{
// if no signature or correct signature
$r = xmlrpc_server_call_method($this->server,$data,$params);
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['incorrect_params'],
$GLOBALS['xmlrpcstr']['incorrect_params'] . ': ' . $sr[1]
);
}
}
else
{
// else prepare error response
if(!$this->authed)
{
// $r = False;
// send 401 header to force authorization
$r = CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval',
'UNAUTHORIZED',
'string'
)
);
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['unknown_method'],
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
);
}
}
xmlrpc_server_destroy($xmlrpc_server);
return $r;
}
function echoInput()
{
// a debugging routine: just echos back the input
// packet as a string value
/* TODO */
// $r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',"'Aha said I: '" . $HTTP_RAW_POST_DATA,'string'));
return $GLOBALS['HTTP_RAW_POST_DATA'];
}
function xmlrpc_custom_error($error_number, $error_string, $filename, $line, $vars)
{
if(error_reporting() & $error_number)
{
$error_string .= sprintf("\nFilename: %s\nLine: %s",$filename,$line);
xmlrpc_error(1005,$error_string);
}
}
/*
function xmlrpc_error($error_number, $error_string)
{
$values = array(
'faultString' => $error_string,
'faultCode' => $error_number
);
echo xmlrpc_encode_request(NULL,$values);
xmlrpc_server_destroy($GLOBALS['xmlrpc_server']);
exit;
}
*/
function xmlrpc_error($error_number, $error_string)
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$error_number,
$error_string . ': ' . $this->last_method
);
$this->service($r);
xmlrpc_server_destroy($GLOBALS['xmlrpc_server']);
exit;
}
}

View File

@ -1,503 +0,0 @@
<?php
// Copyright (c) 1999,2000,2001 Edd Dumbill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of the "XML-RPC for PHP" nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
/*
* Incorporated for egroupware by Miles Lott <milos@groupwhere.org>
*/
/* $Id$ */
/* BEGIN server class */
class xmlrpc_server extends xmlrpc_server_shared
{
var $dmap = array();
var $authed = False;
var $req_array = array();
var $resp_struct = array();
var $debug = False;
var $method_requested;
var $log = False; //'/tmp/xmlrpc.log';
function xmlrpc_server($dispMap='', $serviceNow=0)
{
// dispMap is a dispatch array of methods
// mapped to function names and signatures
// if a method
// doesn't appear in the map then an unknown
// method error is generated
if($dispMap)
{
$this->dmap = $dispMap;
if ($serviceNow)
{
$this->service();
}
}
}
function serializeDebug()
{
if ($GLOBALS['_xmlrpc_debuginfo'] != '')
{
return "<!-- DEBUG INFO:\n\n" . $GLOBALS['_xmlrpc_debuginfo'] . "\n-->\n";
}
else
{
return '';
}
}
function service($r=False)
{
if (!$r) // do we have a response, or we need to parse the request
{
$r = $this->parseRequest();
}
if (!$r)
{
header('WWW-Authenticate: Basic realm="eGroupWare xmlrpc"');
header('HTTP/1.0 401 Unauthorized');
// for the log:
$payload = "WWW-Authenticate: Basic realm=\"eGroupWare xmlrpc\"\nHTTP/1.0 401 Unauthorized\n";
}
else
{
$payload = $GLOBALS['egw']->translation->convert("<?xml version=\"1.0\"?>\n" . $this->serializeDebug() . $r->serialize(),
$GLOBALS['egw']->translation->charset(),'utf-8');
header("Content-type: text/xml");
header("Content-length: " . bytes($payload));
echo $payload;
}
if ($this->log)
{
$fp = fopen($this->log,'a+');
fwrite($fp,"\n\n".date('Y-m-d H:i:s') . " authorized="
. ($this->authed?$GLOBALS['egw_info']['user']['account_lid']:'False')
. ", method='$this->last_method'\n");
fwrite($fp,"==== GOT ============================\n" . $GLOBALS['HTTP_RAW_POST_DATA']
. "\n==== RETURNED =======================\n");
fputs($fp,$payload);
fclose($fp);
}
if ($this->debug)
{
$this->echoInput();
$fp = fopen('/tmp/xmlrpc_debug.out','w');
fputs($fp,$payload);
fclose($fp);
}
}
/*
* add a method to the dispatch map
*/
function add_to_map($methodname,$function,$sig,$doc)
{
$this->dmap[$methodname] = array(
'function' => $function,
'signature' => $sig,
'docstring' => $doc
);
}
function verifySignature($in, $sig)
{
for($i=0; $i<sizeof($sig); $i++)
{
// check each possible signature in turn
$cursig = $sig[$i];
if (sizeof($cursig) == $in->getNumParams()+1)
{
$itsOK = 1;
for($n=0; $n<$in->getNumParams(); $n++)
{
$p = $in->getParam($n);
// print "<!-- $p -->\n";
if ($p->kindOf() == 'scalar')
{
$pt = $p->scalartyp();
}
else
{
$pt = $p->kindOf();
}
// $n+1 as first type of sig is return type
if ($pt != $cursig[$n+1])
{
$itsOK = 0;
$pno = $n+1;
$wanted = $cursig[$n+1];
$got = $pt;
break;
}
}
if ($itsOK)
{
return array(1);
}
}
}
return array(0, "Wanted $wanted, got $got at param $pno)");
}
function reqtoarray($_req,$recursed=False)
{
switch(gettype($_req))
{
case 'object':
if($recursed)
{
return $_req->getval();
}
else
{
$this->req_array = $_req->getval();
}
break;
case 'array':
@reset($_req);
$ele = array();
while(list($key,$val) = @each($_req))
{
if($recursed)
{
$ele[$key] = $this->reqtoarray($val,True);
}
else
{
$this->req_array[$key] = $this->reqtoarray($val,True);
}
}
if($recursed)
{
return $ele;
}
break;
case 'string':
case 'integer':
if($recursed)
{
return $_req;
}
else
{
$this->req_array[] = $_req;
}
break;
default:
break;
}
}
function build_resp($_res)
{
if (is_array($_res))
{
$i = 0;
$is_array = True;
foreach($_res as $key => $val)
{
$ele[$key] = $this->build_resp($val,True);
$is_array = $is_array && $i === $key;
++$i;
}
return CreateObject('phpgwapi.xmlrpcval',$ele,$is_array ? 'array' : 'struct');
}
$_type = (is_integer($_res) ? 'int' : gettype($_res));
if ($_type == 'string' && (preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/',$_res) ||
preg_match('/^[0-9]{4}[0-9]{2}[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/',$_res)))
{
$_type = 'dateTime.iso8601';
}
// Passing an integer of 0 to the xmlrpcval constructor results in the value being lost. (jengo)
if ($_type == 'int' && $_res == 0)
{
return CreateObject('phpgwapi.xmlrpcval','0',$_type);
}
return CreateObject('phpgwapi.xmlrpcval',$_res,$_type);
}
function parseRequest($data='')
{
$r = False;
if ($data == '')
{
$data = $GLOBALS['HTTP_RAW_POST_DATA'];
}
$parser = xml_parser_create($GLOBALS['xmlrpc_defencoding']);
$GLOBALS['_xh'][$parser] = array();
$GLOBALS['_xh'][$parser]['isf'] = 0;
$GLOBALS['_xh'][$parser]['isf_reason'] = '';
$GLOBALS['_xh'][$parser]['params'] = array();
$GLOBALS['_xh'][$parser]['stack']=array();
$GLOBALS['_xh'][$parser]['valuestack'] = array();
$GLOBALS['_xh'][$parser]['method'] = '';
// decompose incoming XML into request structure
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
xml_set_character_data_handler($parser, 'xmlrpc_cd');
xml_set_default_handler($parser, 'xmlrpc_dh');
if (!xml_parse($parser, $data, 1))
{
// return XML error as a faultCode
$r = CreateObject('phpgwapi.xmlrpcresp','',
$GLOBALS['xmlrpcerrxml'] + xml_get_error_code($parser),
sprintf('XML error: %s at line %d',
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser))
);
xml_parser_free($parser);
}
elseif ($GLOBALS['_xh'][$parser]['isf'])
{
xml_parser_free($parser);
$r = CreateObject(
'phpgwapi.xmlrpcresp',
0,
$GLOBALS['xmlrpcerr']['invalid_request'],
$GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh'][$parser]['isf_reason']
);
}
else
{
xml_parser_free($parser);
$m = CreateObject('phpgwapi.xmlrpcmsg',$GLOBALS['_xh'][$parser]['method']);
// now add parameters in
$plist = '';
for($i=0; $i<sizeof($GLOBALS['_xh'][$parser]['params']); $i++)
{
// print "<!-- " . $GLOBALS['_xh'][$parser]['params'][$i]. "-->\n");
$m->addParam($GLOBALS['_xh'][$parser]['params'][$i]);
}
// now to deal with the method
$methName = $GLOBALS['_xh'][$parser]['method'];
$_methName = $GLOBALS['_xh'][$parser]['method'];
$this->last_method = $methName;
if(preg_match('/'."^system\.".'/', $methName))
{
$dmap = $GLOBALS['_xmlrpcs_dmap'];
$sysCall=1;
}
else
{
$dmap = $this->dmap;
$sysCall=0;
}
if(!isset($dmap[$methName]['function']))
{
if($sysCall && $this->authed)
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['unknown_method'],
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
);
return $r;
}
if($this->authed)
{
/* phpgw mod - fetch the (bo) class methods to create the dmap */
// This part is to update session action to match
$this->method_requested = $methName;
$method = $methName;
$tmp = explode('.',$methName);
$methName = $tmp[2];
$service = $tmp[1];
$class = $tmp[0];
if(preg_match('/^service/',$method))
{
$t = 'phpgwapi.' . $class . '.exec';
$dmap = ExecMethod($t,array($service,'list_methods','xmlrpc'));
}
elseif($GLOBALS['egw']->acl->check('run',1,$class))
{
/* This only happens if they have app access. If not, we will
* return a fault below.
*/
$listmeth = $class . '.' . $service . '.' . 'list_methods';
$dmap = ExecMethod($listmeth,'xmlrpc');
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['no_access'],
$GLOBALS['xmlrpcstr']['no_access']
);
return $r;
}
$this->dmap = $dmap;
/* _debug_array($this->dmap);exit; */
}
}
if (isset($dmap[$methName]['function']))
{
// dispatch if exists
if (isset($dmap[$methName]['signature']))
{
list($sr, $errstr) = $this->verifySignature($m, $dmap[$methName]['signature']);
if(!$sr)
{
// Didn't match.
return CreateObject(
'phpgwapi.xmlrpcresp',
0,
$GLOBALS['xmlrpcerr']['incorrect_params'],
$GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
);
}
}
if((!isset($dmap[$methName]['signature'])) || $sr)
{
// if no signature or correct signature
if($sysCall)
{
$r = call_user_func($dmap[$methName]['function'], $this, $m);
}
else
{
if(function_exists($dmap[$methName]['function']))
{
$r = call_user_func($dmap[$methName]['function'],$m);
}
else
{
/* phpgw mod - finally, execute the function call and return the values */
$params = $GLOBALS['_xh'][$parser]['params'][0];
if(count($params) != 0)
{
$p = $params;
$params = $p->getval();
}
// _debug_array($params);
$this->reqtoarray($params);
// decode from utf-8 to our charset
$this->req_array = $GLOBALS['egw']->translation->convert($this->req_array,'utf-8');
//_debug_array($this->req_array);
if (preg_match('/^service/',$method))
{
$res = ExecMethod('phpgwapi.service.exec',array($service,$methName,$this->req_array));
}
else
{
list($s,$c,$m) = explode('.',$_methName);
$res = ExecMethod($s . '.' . $c . '.' . $dmap[$methName]['function'],$this->req_array);
}
//$this->resp_struct = array($this->build_resp($res,True));
//@reset($this->resp_struct);
//$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$this->resp_struct,'struct'));
// this fixes the unnecessary (and not standard-conform) array/xmlrpc struct around everything
$r = CreateObject('phpgwapi.xmlrpcresp',$this->build_resp($res,True));
// _debug_array($r);
}
}
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['incorrect_params'],
$GLOBALS['xmlrpcstr']['incorrect_params'] . ': ' . $sr[1]
);
}
}
else
{
// else prepare error response
if(!$this->authed)
{
$r = False; // send 401 header to force authorization
/*CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval',
'UNAUTHORIZED',
'string'
)
);*/
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$GLOBALS['xmlrpcerr']['unknown_method'],
$GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName
);
}
}
}
unset($GLOBALS['_xh'][$parser]);
return $r;
}
function echoInput()
{
// a debugging routine: just echos back the input
// packet as a string value
$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',"'Aha said I: '"
. $GLOBALS['HTTP_RAW_POST_DATA'],'string'));
//echo $r->serialize();
$fp = fopen('/tmp/xmlrpc_debug.in','w');
fputs($fp,$r->serialize);
fputs($fp,$GLOBALS['HTTP_RAW_POST_DATA']);
fclose($fp);
}
function xmlrpc_error($error_number, $error_string)
{
$r = CreateObject('phpgwapi.xmlrpcresp',
'',
$error_number,
$error_string . ': ' . $this->last_method
);
$this->service($r);
exit;
}
}
?>

View File

@ -1,384 +0,0 @@
<?php
// by Edd Dumbill (C) 1999-2001
// <edd@usefulinc.com>
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
// License is granted to use or modify this software ('XML-RPC for PHP')
// for commercial or non-commercial use provided the copyright of the author
// is preserved in any distributed or derivative work.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* $Id$ */
class xmlrpcmsg
{
var $payload;
var $methodname;
var $params = array();
var $debug = 0;
function xmlrpcmsg($meth, $pars=0)
{
$this->methodname=$meth;
if(is_array($pars) && sizeof($pars)>0)
{
for($i=0; $i<sizeof($pars); $i++)
{
$this->addParam($pars[$i]);
}
}
}
function xml_header()
{
return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
}
function xml_footer()
{
return "</methodCall>\n";
}
function createPayload()
{
$this->payload=$this->xml_header();
$this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
// if(sizeof($this->params)) {
$this->payload.="<params>\n";
for($i=0; $i<sizeof($this->params); $i++)
{
$p=$this->params[$i];
$this->payload.="<param>\n" . $p->serialize() .
"</param>\n";
}
$this->payload.="</params>\n";
// }
$this->payload.=$this->xml_footer();
//$this->payload=str_replace("\n", "\r\n", $this->payload);
}
function method($meth='')
{
if($meth!='')
{
$this->methodname=$meth;
}
return $this->methodname;
}
function serialize()
{
$this->createPayload();
return $this->payload;
}
function addParam($par)
{
// add check: do not add to self params which are not xmlrpcvals
if(is_object($par) && (get_class($par) == 'xmlrpcval' || is_subclass_of($par, 'xmlrpcval')))
{
$this->params[]=$par;
return true;
}
else
{
return false;
}
}
function getParam($i) { return $this->params[$i]; }
function getNumParams() { return sizeof($this->params); }
function &parseResponseFile($fp)
{
$ipd='';
while($data=fread($fp, 32768))
{
$ipd.=$data;
}
//fclose($fp);
$r =& $this->parseResponse($ipd);
return $r;
}
function &parseResponse($data='', $headers_processed=false)
{
$parser = xml_parser_create($GLOBALS['xmlrpc_defencoding']);
$hdrfnd = 0;
if($this->debug)
{
//by maHo, replaced htmlspecialchars with htmlentities
print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
}
if($data == '')
{
error_log('No response received from server.');
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
return $r;
}
// see if we got an HTTP 200 OK, else bomb
// but only do this if we're using the HTTP protocol.
if(preg_match('/'."^HTTP".'/',$data))
{
// Strip HTTP 1.1 100 Continue header if present
while(preg_match('/^HTTP\\/1.1 1[0-9]{2} /', $data))
{
$pos = strpos($data, 'HTTP', 12);
// server sent a Continue header without any (valid) content following...
// give the client a chance to know it
if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
{
break;
}
$data = substr($data, $pos);
}
if(!preg_match('/'."^HTTP\\/[0-9\\.]+ 200 ".'/', $data))
{
$errstr= substr($data, 0, strpos($data, "\n")-1);
error_log('HTTP error, got response: ' .$errstr);
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
return $r;
}
}
$GLOBALS['_xh'][$parser] = array();
$GLOBALS['_xh'][$parser]['headers'] = array();
$GLOBALS['_xh'][$parser]['stack'] = array();
$GLOBALS['_xh'][$parser]['valuestack'] = array();
// separate HTTP headers from data
if(preg_match('/'."^HTTP".'/', $data))
{
// be tolerant to usage of \n instead of \r\n to separate headers and data
// (even though it is not valid http)
$pos = strpos($data,"\r\n\r\n");
if($pos || is_int($pos))
{
$bd = $pos+4;
}
else
{
$pos = strpos($data,"\n\n");
if($pos || is_int($pos))
{
$bd = $pos+2;
}
else
{
// No separation between response headers and body: fault?
$bd = 0;
}
}
// be tolerant to line endings, and extra empty lines
$ar = preg_split("/\r?\n/", trim(substr($data, 0, $pos)));
while(list(,$line) = @each($ar))
{
// take care of multi-line headers
$arr = explode(':',$line);
if(count($arr) > 1)
{
$header_name = strtolower(trim($arr[0]));
// TO DO: some headers (the ones that allow a CSV list of values)
// do allow many values to be passed using multiple header lines.
// We should add content to $GLOBALS['_xh'][$parser]['headers'][$header_name]
// instead of replacing it for those...
$GLOBALS['_xh'][$parser]['headers'][$header_name] = $arr[1];
for($i = 2; $i < count($arr); $i++)
{
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ':'.$arr[$i];
} // while
$GLOBALS['_xh'][$parser]['headers'][$header_name] = trim($GLOBALS['_xh'][$parser]['headers'][$header_name]);
}
elseif(isset($header_name))
{
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ' ' . trim($line);
}
}
$data = substr($data, $bd);
if($this->debug && count($GLOBALS['_xh'][$parser]['headers']))
{
print '<PRE>';
foreach($GLOBALS['_xh'][$parser]['headers'] as $header => $value)
{
print "HEADER: $header: $value\n";
}
print "</PRE>\n";
}
}
// if CURL was used for the call, http headers have been processed,
// and dechunking + reinflating have been carried out
if(!$headers_processed)
{
// Decode chunked encoding sent by http 1.1 servers
if(isset($GLOBALS['_xh'][$parser]['headers']['transfer-encoding']) && $GLOBALS['_xh'][$parser]['headers']['transfer-encoding'] == 'chunked')
{
if(!$data = decode_chunked($data))
{
error_log('Errors occurred when trying to rebuild the chunked data received from server');
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
return $r;
}
}
// Decode gzip-compressed stuff
// code shamelessly inspired from nusoap library by Dietrich Ayala
if(isset($GLOBALS['_xh'][$parser]['headers']['content-encoding']))
{
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip')
{
// if decoding works, use it. else assume data wasn't gzencoded
if(function_exists('gzinflate'))
{
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' && $degzdata = @gzinflate($data))
{
$data = $degzdata;
if($this->debug)
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
}
elseif($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
{
$data = $degzdata;
if($this->debug)
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
}
else
{
error_log('Errors occurred when trying to decode the deflated data received from server');
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
return $r;
}
}
else
{
error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
return $r;
}
}
}
} // end of 'de-chunk, re-inflate response'
// be tolerant of extra whitespace in response body
$data = trim($data);
// be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
// idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
$bd = false;
$pos = strpos($data, '</methodResponse>');
while($pos || is_int($pos))
{
$bd = $pos+17;
$pos = strpos($data, '</methodResponse>', $bd);
}
if($bd)
{
$data = substr($data, 0, $bd);
}
$GLOBALS['_xh'][$parser]['isf']=0;
$GLOBALS['_xh'][$parser]['isf_reason']='';
$GLOBALS['_xh'][$parser]['ac']='';
$GLOBALS['_xh'][$parser]['qt']='';
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
// the xml parser to give us back data in the expected charset
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
xml_set_character_data_handler($parser, 'xmlrpc_cd');
xml_set_default_handler($parser, 'xmlrpc_dh');
//$xmlrpc_value=new xmlrpcval;
if(!xml_parse($parser, $data, sizeof($data)))
{
// thanks to Peter Kocks <peter.kocks@baygate.com>
if((xml_get_current_line_number($parser)) == 1)
{
$errstr = 'XML error at line 1, check URL';
}
else
{
$errstr = sprintf('XML error: %s at line %d',
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser));
}
error_log($errstr);
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
xml_parser_free($parser);
if($this->debug)
{
print $errstr;
}
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
return $r;
}
xml_parser_free($parser);
if($GLOBALS['_xh'][$parser]['isf'] > 1)
{
if ($this->debug)
{
///@todo echo something for user?
}
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
$GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh'][$parser]['isf_reason']);
}
elseif (!is_object($GLOBALS['_xh'][$parser]['value']))
{
// then something odd has happened
// and it's time to generate a client side error
// indicating something odd went on
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
$GLOBALS['xmlrpcstr']['invalid_return']);
}
else
{
if ($this->debug)
{
print "<PRE>---PARSED---\n" ;
var_dump($GLOBALS['_xh'][$parser]['value']);
print "\n---END---</PRE>";
} // note that using =& will raise an error if $GLOBALS['_xh'][$parser]['st'] does not generate an object.
$v = $GLOBALS['_xh'][$parser]['value'];
if($GLOBALS['_xh'][$parser]['isf'])
{
$errno_v = $v->structmem('faultCode');
$errstr_v = $v->structmem('faultString');
$errno = $errno_v->scalarval();
if($errno == 0)
{
// FAULT returned, errno needs to reflect that
$errno = -1;
}
$r =& CreateObject('phpgwapi.xmlrpcresp',$v, $errno, $errstr_v->scalarval());
}
else
{
$r=& CreateObject('phpgwapi.xmlrpcresp',$v);
}
}
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
return $r;
}
}
?>

View File

@ -1,97 +0,0 @@
<?php
// by Edd Dumbill (C) 1999-2001
// <edd@usefulinc.com>
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
// License is granted to use or modify this software ("XML-RPC for PHP")
// for commercial or non-commercial use provided the copyright of the author
// is preserved in any distributed or derivative work.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
class xmlrpcresp
{
var $val = 0;
var $errno = 0;
var $errstr = '';
var $hdrs = array();
/// @todo add check that $val is of correct type???
function xmlrpcresp($val, $fcode = 0, $fstr = '')
{
if($fcode != 0)
{
// error
$this->errno = $fcode;
$this->errstr = $fstr;
//$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
}
elseif(!is_object($val) || (get_class($val) != 'xmlrpcval' && !is_subclass_of($val, 'xmlrpcval')))
{
// programmer error
// TODO
error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
$this->val = new xmlrpcval();
}
else
{
// success
$this->val = $val;
}
}
function faultCode()
{
return $this->errno;
}
function faultString()
{
return $this->errstr;
}
function value()
{
return $this->val;
}
function serialize()
{
$result = "<methodResponse>\n";
if($this->errno)
{
// G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
$result .= '<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>' . $this->errno . '</int></value>
</member>
<member>
<name>faultString</name>
<value><string>' . xmlrpc_encode_entities($this->errstr) . '</string></value>
</member>
</struct>
</value>
</fault>';
}
else
{
$result .= "<params>\n<param>\n" .
$this->val->serialize() .
"</param>\n</params>";
}
$result .= "\n</methodResponse>";
return $result;
}
}

View File

@ -1,333 +0,0 @@
<?php
// by Edd Dumbill (C) 1999-2001
// <edd@usefulinc.com>
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
// License is granted to use or modify this software ("XML-RPC for PHP")
// for commercial or non-commercial use provided the copyright of the author
// is preserved in any distributed or derivative work.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* $Id$ */
class xmlrpcval
{
var $me=array();
var $mytype=0;
function xmlrpcval($val=-1, $type='')
{
//$this->me=array();
//$this->mytype=0;
if($val!==-1 || $type!='')
{
if($type=='')
{
$type='string';
}
if($GLOBALS['xmlrpcTypes'][$type]==1)
{
$this->addScalar($val,$type);
}
elseif($GLOBALS['xmlrpcTypes'][$type]==2)
{
$this->addArray($val);
}
elseif($GLOBALS['xmlrpcTypes'][$type]==3)
{
$this->addStruct($val);
}
}
}
function addScalar($val, $type='string')
{
$typeof=@$GLOBALS['xmlrpcTypes'][$type];
if($typeof!=1)
{
error_log("addScalar: not a scalar type ($typeof)");
return 0;
}
// coerce booleans into correct values
// NB: shall we do it for datetime too?
if($type == xmlrpcBoolean)
{
if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
{
$val=true;
}
else
{
$val=false;
}
}
switch($this->mytype)
{
case 1:
error_log('addScalar: scalar xmlrpcval can have only one value');
return 0;
case 3:
error_log('addScalar: cannot add anonymous scalar to struct xmlrpcval');
return 0;
case 2:
// we're adding a scalar value to an array here
//$ar=$this->me['array'];
//$ar[]= new xmlrpcval($val, $type);
//$this->me['array']=$ar;
// Faster (?) avoid all the costly array-copy-by-val done here...
$this->me['array'][]=& CreateObject('phpgwapi.xmlrpcval',$val, $type);
return 1;
default:
// a scalar, so set the value and remember we're scalar
$this->me[$type]=$val;
$this->mytype=$typeof;
return 1;
}
}
///@todo add some checking for $vals to be an array of xmlrpcvals?
function addArray($vals)
{
if($this->mytype==0)
{
$this->mytype=$GLOBALS['xmlrpcTypes']['array'];
$this->me['array']=$vals;
return 1;
}
elseif($this->mytype==2)
{
// we're adding to an array here
$this->me['array'] = array_merge($this->me['array'], $vals);
}
else
{
error_log('xmlrpcval: already initialized as a [' . $this->kindOf() . ']');
return 0;
}
}
///@todo add some checking for $vals to be an array?
function addStruct($vals)
{
if($this->mytype==0)
{
$this->mytype = $GLOBALS['xmlrpcTypes']['struct'];
$this->me['struct']=$vals;
return 1;
}
elseif($this->mytype==3)
{
// we're adding to a struct here
$this->me['struct'] = array_merge($this->me['struct'], $vals);
}
else
{
error_log('xmlrpcval: already initialized as a [' . $this->kindOf() . ']');
return 0;
}
}
function dump($ar)
{
foreach($ar as $key => $val)
{
echo "$key => $val<br />";
if($key == 'array')
{
while(list($key2, $val2) = each($val))
{
echo "-- $key2 => $val2<br />";
}
}
}
}
function kindOf()
{
switch($this->mytype)
{
case 3:
return 'struct';
break;
case 2:
return 'array';
break;
case 1:
return 'scalar';
break;
default:
return 'undef';
}
}
function serializedata($typ, $val)
{
$rs='';
switch(@$GLOBALS['xmlrpcTypes'][$typ])
{
case 3:
// struct
$rs.="<struct>\n";
foreach($val as $key2 => $val2)
{
$rs.="<member><name>${key2}</name>\n";
$rs.=$this->serializeval($val2);
$rs.="</member>\n";
}
$rs.='</struct>';
break;
case 2:
// array
$rs.="<array>\n<data>\n";
for($i=0; $i<sizeof($val); $i++)
{
$rs.=$this->serializeval($val[$i]);
}
$rs.="</data>\n</array>";
break;
case 1:
switch($typ)
{
case xmlrpcBase64:
$rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
break;
case xmlrpcBoolean:
$rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
break;
case xmlrpcString:
// G. Giunta 2005/2/13: do NOT use htmlentities, since
// it will produce named html entities, which are invalid xml
$rs.="<${typ}>" . xmlrpc_encode_entities($val). "</${typ}>";
// $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
break;
default:
$rs.="<${typ}>${val}</${typ}>";
}
break;
default:
break;
}
return $rs;
}
function serialize()
{
return $this->serializeval($this);
}
function serializeval($o)
{
// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
//{
$ar=$o->me;
reset($ar);
list($typ, $val) = each($ar);
return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
//}
}
function structmemexists($m)
{
return array_key_exists($this->me['struct'][$m]);
}
function structmem($m)
{
return $this->me['struct'][$m];
}
function structreset()
{
reset($this->me['struct']);
}
function structeach()
{
return each($this->me['struct']);
}
function scalarval()
{
reset($this->me);
list(,$b)=each($this->me);
return $b;
}
function scalartyp()
{
reset($this->me);
list($a,$b)=each($this->me);
if($a == xmlrpcI4)
{
$a = xmlrpcInt;
}
return $a;
}
function arraymem($m)
{
return $this->me['array'][$m];
}
function arraysize()
{
return count($this->me['array']);
}
function structsize()
{
return count($this->me['struct']);
}
// DEPRECATED! this code looks like it is very fragile and has not been fixed
// for a long long time. Shall we remove it for 2.0?
function getval()
{
// UNSTABLE ?
reset($this->me);
list($a,$b)=each($this->me);
// contributed by I Sofer, 2001-03-24
// add support for nested arrays to scalarval
// i've created a new method here, so as to
// preserve back compatibility
if(is_array($b))
{
foreach($b as $id => $cont)
{
$b[$id] = $cont->scalarval();
}
}
// add support for structures directly encoding php objects
if(is_object($b))
{
$t = get_object_vars($b);
foreach($t as $id => $cont)
{
$t[$id] = $cont->scalarval();
}
foreach($t as $id => $cont)
{
@$b->$id = $cont;
}
}
// end contrib
return $b;
}
}
?>

View File

@ -1,960 +0,0 @@
<?php
// by Edd Dumbill (C) 1999-2001
// <edd@usefulinc.com>
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
// License is granted to use or modify this software ("XML-RPC for PHP")
// for commercial or non-commercial use provided the copyright of the author
// is preserved in any distributed or derivative work.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* $Id$ */
if (!function_exists('xml_parser_create'))
{
// Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
if($WINDIR)
{
dl('php3_xml.dll');
}
else
{
dl('xml.so');
}
}
$GLOBALS['xmlrpc_valid_parents'] = array(
'BOOLEAN' => array('VALUE'),
'I4' => array('VALUE'),
'INT' => array('VALUE'),
'STRING' => array('VALUE'),
'DOUBLE' => array('VALUE'),
'DATETIME.ISO8601' => array('VALUE'),
'BASE64' => array('VALUE'),
'ARRAY' => array('VALUE'),
'STRUCT' => array('VALUE'),
'PARAM' => array('PARAMS'),
'METHODNAME' => array('METHODCALL'),
'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
'MEMBER' => array('STRUCT'),
'NAME' => array('MEMBER'),
'DATA' => array('ARRAY'),
'FAULT' => array('METHODRESPONSE'),
'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
);
define('xmlrpcI4','i4');
define('xmlrpcInt','int');
define('xmlrpcBoolean','boolean');
define('xmlrpcDouble','double');
define('xmlrpcString','string');
define('xmlrpcDateTime','dateTime.iso8601');
define('xmlrpcBase64','base64');
define('xmlrpcArray','array');
define('xmlrpcStruct','struct');
$GLOBALS['xmlrpcTypes'] = array(
xmlrpcI4 => 1,
xmlrpcInt => 1,
xmlrpcBoolean => 1,
xmlrpcString => 1,
xmlrpcDouble => 1,
xmlrpcDateTime => 1,
xmlrpcBase64 => 1,
xmlrpcArray => 2,
xmlrpcStruct => 3
);
$GLOBALS['xmlEntities']=array(
'amp' => '&',
'quot' => '"',
'lt' => '<',
'gt' => '>',
'apos' => "'"
);
$GLOBALS['xmlrpcerr']['unknown_method']=1;
$GLOBALS['xmlrpcstr']['unknown_method']='Unknown method';
$GLOBALS['xmlrpcerr']['invalid_return']=2;
$GLOBALS['xmlrpcstr']['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
$GLOBALS['xmlrpcerr']['incorrect_params']=3;
$GLOBALS['xmlrpcstr']['incorrect_params']='Incorrect parameters passed to method';
$GLOBALS['xmlrpcerr']['introspect_unknown']=4;
$GLOBALS['xmlrpcstr']['introspect_unknown']="Can't introspect: method unknown";
$GLOBALS['xmlrpcerr']['http_error']=5;
$GLOBALS['xmlrpcstr']['http_error']="Didn't receive 200 OK from remote server.";
$GLOBALS['xmlrpcerr']['no_data']=6;
$GLOBALS['xmlrpcstr']['no_data']='No data received from server.';
$GLOBALS['xmlrpcerr']['no_ssl']=7;
$GLOBALS['xmlrpcstr']['no_ssl']='No SSL support compiled in.';
$GLOBALS['xmlrpcerr']['curl_fail']=8;
$GLOBALS['xmlrpcstr']['curl_fail']='CURL error';
$GLOBALS['xmlrpcerr']['multicall_notstruct'] = 9;
$GLOBALS['xmlrpcstr']['multicall_notstruct'] = 'system.multicall expected struct';
$GLOBALS['xmlrpcerr']['multicall_nomethod'] = 10;
$GLOBALS['xmlrpcstr']['multicall_nomethod'] = 'missing methodName';
$GLOBALS['xmlrpcerr']['multicall_notstring'] = 11;
$GLOBALS['xmlrpcstr']['multicall_notstring'] = 'methodName is not a string';
$GLOBALS['xmlrpcerr']['multicall_recursion'] = 12;
$GLOBALS['xmlrpcstr']['multicall_recursion'] = 'recursive system.multicall forbidden';
$GLOBALS['xmlrpcerr']['multicall_noparams'] = 13;
$GLOBALS['xmlrpcstr']['multicall_noparams'] = 'missing params';
$GLOBALS['xmlrpcerr']['multicall_notarray'] = 14;
$GLOBALS['xmlrpcstr']['multicall_notarray'] = 'params is not an array';
$GLOBALS['xmlrpcerr']['invalid_request']=15;
$GLOBALS['xmlrpcstr']['invalid_request']='Invalid request payload';
$GLOBALS['xmlrpcerr']['no_curl']=16;
$GLOBALS['xmlrpcstr']['no_curl']='No CURL support compiled in.';
$GLOBALS['xmlrpcerr']['server_error']=17;
$GLOBALS['xmlrpcstr']['server_error']='Internal server error';
$GLOBALS['xmlrpcerr']['no_access'] = 18;
$GLOBALS['xmlrpcstr']['no_access'] = 'Access denied';
$GLOBALS['xmlrpcerr']['not_existent'] = 19;
$GLOBALS['xmlrpcstr']['not_existent'] = 'Entry does not (longer) exist!';
$GLOBALS['xmlrpcerr']['cannot_decompress']=103;
$GLOBALS['xmlrpcstr']['cannot_decompress']='Received from server compressed HTTP and cannot decompress';
$GLOBALS['xmlrpcerr']['decompress_fail']=104;
$GLOBALS['xmlrpcstr']['decompress_fail']='Received from server invalid compressed HTTP';
$GLOBALS['xmlrpcerr']['dechunk_fail']=105;
$GLOBALS['xmlrpcstr']['dechunk_fail']='Received from server invalid chunked HTTP';
$GLOBALS['xmlrpcerr']['server_cannot_decompress']=106;
$GLOBALS['xmlrpcstr']['server_cannot_decompress']='Received from client compressed HTTP request and cannot decompress';
$GLOBALS['xmlrpcerr']['server_decompress_fail']=107;
$GLOBALS['xmlrpcstr']['server_decompress_fail']='Received from client invalid compressed HTTP request';
$GLOBALS['xmlrpc_defencoding'] = 'UTF-8';
$GLOBALS['xmlrpc_internalencoding']='ISO-8859-1';
$GLOBALS['xmlrpcName'] = 'XML-RPC for PHP';
$GLOBALS['xmlrpcVersion'] = '2.0';
// let user errors start at 800
$GLOBALS['xmlrpcerruser'] = 800;
// let XML parse errors start at 100
$GLOBALS['xmlrpcerrxml'] = 100;
// formulate backslashes for escaping regexp
$GLOBALS['xmlrpc_backslash'] = chr(92) . chr(92);
/*!
@function xmlrpcfault
@abstract Error reporting for XML-RPC
@discussion Author: jengo <br>
Returns XML-RPC fault and stops this execution of the application. <br>
Syntax: void xmlrpcfault(string) <br>
Example1: xmlrpcfault('Session could not be verifed'); <br>
@param $string Error message to be returned.
*/
function xmlrpcfault($string)
{
$r = CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval'),
$GLOBALS['xmlrpcerr']['unknown_method'],
$string
);
$payload = '<?xml version="1.0"?>' . "\n" . $r->serialize();
Header('Content-type: text/xml');
Header('Content-length: ' . bytes($payload));
print $payload;
$GLOBALS['egw']->common->phpgw_exit(False);
}
// used to store state during parsing
// quick explanation of components:
// ac - used to accumulate values
// isf - used to indicate a fault
// lv - used to indicate "looking for a value": implements
// the logic to allow values with no types to be strings
// params - used to store parameters in method calls
// method - used to store method name
// stack - array with genealogy of xml elements names:
// used to validate nesting of xmlrpc elements
$GLOBALS['_xh'] = null;
/**
* To help correct communication of non-ascii chars inside strings, regardless
* of the charset used when sending requests, parsing them, sending responses
* and parsing responses, convert all non-ascii chars present in the message
* into their equivalent 'charset entity'. Charset entities enumerated this way
* are independent of the charset encoding used to transmit them, and all XML
* parsers are bound to understand them.
*
* @author Eugene Pivnev
*/
function xmlrpc_encode_entities($data)
{
return htmlspecialchars($data,ENT_QUOTES,$GLOBALS['egw']->translation->system_charset ?
$GLOBALS['egw']->translation->system_charset : 'UTF-8');
}
if (!function_exists('htmlspecialchars_decode')) // php < 5.1
{
function htmlspecialchars_decode($text,$quote_style=ENT_COMPAT)
{
return strtr($text, array_flip(get_html_translation_table(HTML_SPECIALCHARS,$quote_style)));
}
}
function xmlrpc_entity_decode($string)
{
return htmlspecialchars_decode($data,ENT_QUOTES);
}
function xmlrpc_lookup_entity($ent)
{
if (isset($GLOBALS['xmlEntities'][strtolower($ent)]))
{
return $GLOBALS['xmlEntities'][strtolower($ent)];
}
if (preg_match('/'."^#([0-9]+)$".'/', $ent, $regs))
{
return chr($regs[1]);
}
return '?';
}
function xmlrpc_se($parser, $name, $attrs)
{
// if invalid xmlrpc already detected, skip all processing
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
{
// check for correct element nesting
// top level element can only be of 2 types
if (count($GLOBALS['_xh'][$parser]['stack']) == 0)
{
if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
{
$GLOBALS['_xh'][$parser]['isf'] = 2;
$GLOBALS['_xh'][$parser]['isf_reason'] = 'missing top level xmlrpc element';
return;
}
}
else
{
// not top level element: see if parent is OK
if (!in_array($GLOBALS['_xh'][$parser]['stack'][0], $GLOBALS['xmlrpc_valid_parents'][$name]))
{
$GLOBALS['_xh'][$parser]['isf'] = 2;
$GLOBALS['_xh'][$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$GLOBALS['_xh'][$parser]['stack'][0]}";
return;
}
}
switch($name)
{
case 'STRUCT':
case 'ARRAY':
// create an empty array to hold child values, and push it onto appropriate stack
$cur_val = array();
$cur_val['values'] = array();
$cur_val['type'] = $name;
@array_unshift($GLOBALS['_xh'][$parser]['valuestack'], $cur_val);
break;
case 'DATA':
case 'METHODCALL':
case 'METHODRESPONSE':
case 'PARAMS':
// valid elements that add little to processing
break;
case 'METHODNAME':
case 'NAME':
$GLOBALS['_xh'][$parser]['ac']='';
break;
case 'FAULT':
$GLOBALS['_xh'][$parser]['isf']=1;
break;
case 'VALUE':
$GLOBALS['_xh'][$parser]['vt']='value'; // indicator: no value found yet
$GLOBALS['_xh'][$parser]['ac']='';
$GLOBALS['_xh'][$parser]['lv']=1;
break;
case 'I4':
case 'INT':
case 'STRING':
case 'BOOLEAN':
case 'DOUBLE':
case 'DATETIME.ISO8601':
case 'BASE64':
if ($GLOBALS['_xh'][$parser]['vt']!='value')
{
//two data elements inside a value: an error occurred!
$GLOBALS['_xh'][$parser]['isf'] = 2;
$GLOBALS['_xh'][$parser]['isf_reason'] = "$name element following a {$GLOBALS['_xh'][$parser]['vt']} element inside a single value";
return;
}
$GLOBALS['_xh'][$parser]['ac']=''; // reset the accumulator
break;
case 'MEMBER':
$GLOBALS['_xh'][$parser]['valuestack'][0]['name']=''; // set member name to null, in case we do not find in the xml later on
//$GLOBALS['_xh'][$parser]['ac']='';
// Drop trough intentionally
case 'PARAM':
// clear value, so we can check later if no value will passed for this param/member
$GLOBALS['_xh'][$parser]['value']=null;
break;
default:
/// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
$GLOBALS['_xh'][$parser]['isf'] = 2;
$GLOBALS['_xh'][$parser]['isf_reason'] = "found not-xmlrpc xml element $name";
break;
}
// Save current element name to stack, to validate nesting
@array_unshift($GLOBALS['_xh'][$parser]['stack'], $name);
if($name!='VALUE')
{
$GLOBALS['_xh'][$parser]['lv']=0;
}
}
}
function xmlrpc_ee($parser, $name)
{
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
{
// push this element name from stack
// NB: if XML validates, correct opening/closing is guaranteed and
// we do not have to check for $name == $curr_elem.
// we also checked for proper nesting at start of elements...
$curr_elem = array_shift($GLOBALS['_xh'][$parser]['stack']);
switch($name)
{
case 'STRUCT':
case 'ARRAY':
// fetch out of stack array of values, and promote it to current value
$curr_val = array_shift($GLOBALS['_xh'][$parser]['valuestack']);
$GLOBALS['_xh'][$parser]['value'] = $curr_val['values'];
$GLOBALS['_xh'][$parser]['vt']=strtolower($name);
break;
case 'NAME':
$GLOBALS['_xh'][$parser]['valuestack'][0]['name'] = $GLOBALS['_xh'][$parser]['ac'];
break;
case 'BOOLEAN':
case 'I4':
case 'INT':
case 'STRING':
case 'DOUBLE':
case 'DATETIME.ISO8601':
case 'BASE64':
$GLOBALS['_xh'][$parser]['vt']=strtolower($name);
if ($name=='STRING')
{
$GLOBALS['_xh'][$parser]['value']=$GLOBALS['_xh'][$parser]['ac'];
}
elseif ($name=='DATETIME.ISO8601')
{
$GLOBALS['_xh'][$parser]['vt'] = xmlrpcDateTime;
$GLOBALS['_xh'][$parser]['value']=$GLOBALS['_xh'][$parser]['ac'];
}
elseif ($name=='BASE64')
{
///@todo check for failure of base64 decoding / catch warnings
$GLOBALS['_xh'][$parser]['value'] = base64_decode($GLOBALS['_xh'][$parser]['ac']);
}
elseif ($name=='BOOLEAN')
{
// special case here: we translate boolean 1 or 0 into PHP
// constants true or false
// NB: this simple checks helps a lot sanitizing input, ie no
// security problems around here
if ($GLOBALS['_xh'][$parser]['ac']=='1')
{
$GLOBALS['_xh'][$parser]['value']=true;
}
else
{
// log if receiveing something strange, even though we set the value to false anyway
if ($GLOBALS['_xh'][$parser]['ac']!='0')
error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh'][$parser]['ac']);
$GLOBALS['_xh'][$parser]['value']=false;
}
}
elseif ($name=='DOUBLE')
{
// we have a DOUBLE
// we must check that only 0123456789-.<space> are characters here
if (!preg_match('/^[+-]?[eE0123456789 \\t\\.]+$/', $GLOBALS['_xh'][$parser]['ac']))
{
// TODO: find a better way of throwing an error
// than this!
error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh'][$parser]['ac']);
$GLOBALS['_xh'][$parser]['value']='ERROR_NON_NUMERIC_FOUND';
}
else
{
// it's ok, add it on
$GLOBALS['_xh'][$parser]['value']=(double)$GLOBALS['_xh'][$parser]['ac'];
}
}
else
{
// we have an I4/INT
// we must check that only 0123456789-<space> are characters here
if (!preg_match('/^[+-]?[0123456789 \\t]+$/', $GLOBALS['_xh'][$parser]['ac']))
{
// TODO: find a better way of throwing an error
// than this!
error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh'][$parser]['ac']);
$GLOBALS['_xh'][$parser]['value']='ERROR_NON_NUMERIC_FOUND';
}
else
{
// it's ok, add it on
$GLOBALS['_xh'][$parser]['value'] = (int)$GLOBALS['_xh'][$parser]['ac'];
}
}
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
$GLOBALS['_xh'][$parser]['lv']=3; // indicate we've found a value
break;
case 'VALUE':
// This if() detects if no scalar was inside <VALUE></VALUE>
if ($GLOBALS['_xh'][$parser]['vt'] == 'value')
{
$GLOBALS['_xh'][$parser]['value'] = $GLOBALS['_xh'][$parser]['ac'];
$GLOBALS['_xh'][$parser]['vt'] = xmlrpcString;
}
// build the xmlrpc val out of the data received, and substitute it
$temp =& CreateObject('phpgwapi.xmlrpcval',$GLOBALS['_xh'][$parser]['value'], $GLOBALS['_xh'][$parser]['vt']);
// check if we are inside an array or struct:
// if value just built is inside an array, let's move it into array on the stack
if (count($GLOBALS['_xh'][$parser]['valuestack']) && $GLOBALS['_xh'][$parser]['valuestack'][0]['type']=='ARRAY')
{
$GLOBALS['_xh'][$parser]['valuestack'][0]['values'][] = $temp;
}
else
{
$GLOBALS['_xh'][$parser]['value'] = $temp;
}
break;
case 'MEMBER':
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
// add to array in the stack the last element built,
// unless no VALUE was found
if ($GLOBALS['_xh'][$parser]['value'])
$GLOBALS['_xh'][$parser]['valuestack'][0]['values'][$GLOBALS['_xh'][$parser]['valuestack'][0]['name']] = $GLOBALS['_xh'][$parser]['value'];
else
error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
break;
case 'DATA':
$GLOBALS['_xh'][$parser]['ac']=''; // is this necessary?
break;
case 'PARAM':
// add to array of params the current value,
// unless no VALUE was found
if ($GLOBALS['_xh'][$parser]['value'])
$GLOBALS['_xh'][$parser]['params'][]=$GLOBALS['_xh'][$parser]['value'];
else
error_log('XML-RPC: missing VALUE inside PARAM in received xml');
break;
case 'METHODNAME':
$GLOBALS['_xh'][$parser]['method']=preg_replace('/'."^[\n\r\t ]+".'/', '', $GLOBALS['_xh'][$parser]['ac']);
break;
case 'PARAMS':
case 'FAULT':
case 'METHODCALL':
case 'METHORESPONSE':
break;
default:
// End of INVALID ELEMENT!
// shall we add an assert here for unreachable code???
break;
}
}
}
function xmlrpc_cd($parser, $data)
{
//if(preg_match('/'."^[\n\r \t]+$".'/', $data)) return;
// print "adding [${data}]\n";
// skip processing if xml fault already detected
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
{
if($GLOBALS['_xh'][$parser]['lv']!=3)
{
// "lookforvalue==3" means that we've found an entire value
// and should discard any further character data
if($GLOBALS['_xh'][$parser]['lv']==1)
{
// if we've found text and we're just in a <value> then
// say we've found a value
$GLOBALS['_xh'][$parser]['lv']=2;
}
if(!@isset($GLOBALS['_xh'][$parser]['ac']))
{
$GLOBALS['_xh'][$parser]['ac'] = '';
}
$GLOBALS['_xh'][$parser]['ac'].=$data;
}
}
}
function xmlrpc_dh($parser, $data)
{
// skip processing if xml fault already detected
if ($GLOBALS['_xh'][$parser]['isf'] < 2)
{
if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
{
if($GLOBALS['_xh'][$parser]['lv']==1)
{
$GLOBALS['_xh'][$parser]['lv']=2;
}
$GLOBALS['_xh'][$parser]['ac'].=$data;
}
}
}
// date helpers
function iso8601_encode($timet, $utc=0)
{
// return an ISO8601 encoded string
// really, timezones ought to be supported
// but the XML-RPC spec says:
//
// "Don't assume a timezone. It should be specified by the server in its
// documentation what assumptions it makes about timezones."
//
// these routines always assume localtime unless
// $utc is set to 1, in which case UTC is assumed
// and an adjustment for locale is made when encoding
if (!$utc)
{
$t=strftime("%Y%m%dT%H:%M:%S", $timet);
}
else
{
if(function_exists('gmstrftime'))
{
// gmstrftime doesn't exist in some versions
// of PHP
$t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
}
else
{
$t = strftime('%Y%m%dT%H:%M:%S', $timet-date('Z'));
}
}
return $t;
}
function iso8601_decode($idate, $utc=0)
{
// return a time in the localtime, or UTC
$t = 0;
if (preg_match('/'."([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})".'/',$idate, $regs))
{
if ($utc)
{
$t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
}
else
{
$t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
}
}
return $t;
}
/****************************************************************
* xmlrpc_decode takes a message in PHP xmlrpc object format and *
* tranlates it into native PHP types. *
* *
* author: Dan Libby (dan@libby.com) *
****************************************************************/
function phpgw_xmlrpc_decode($xmlrpc_val)
{
$kind = @$xmlrpc_val->kindOf();
if($kind == 'scalar')
{
return $xmlrpc_val->scalarval();
}
elseif($kind == 'array')
{
$size = $xmlrpc_val->arraysize();
$arr = array();
for($i = 0; $i < $size; $i++)
{
$arr[] = phpgw_xmlrpc_decode($xmlrpc_val->arraymem($i));
}
return $arr;
}
elseif($kind == 'struct')
{
$xmlrpc_val->structreset();
$arr = array();
while(list($key,$value)=$xmlrpc_val->structeach())
{
$arr[$key] = phpgw_xmlrpc_decode($value);
}
return $arr;
}
}
/****************************************************************
* xmlrpc_encode takes native php types and encodes them into *
* xmlrpc PHP object format. *
* BUG: All sequential arrays are turned into structs. I don't *
* know of a good way to determine if an array is sequential *
* only. *
* *
* feature creep -- could support more types via optional type *
* argument. *
* *
* author: Dan Libby (dan@libby.com) *
****************************************************************/
function phpgw_xmlrpc_encode($php_val)
{
$type = gettype($php_val);
$xmlrpc_val = CreateObject('phpgwapi.xmlrpcval');
switch($type)
{
case 'array':
case 'object':
$arr = array();
while(list($k,$v) = each($php_val))
{
$arr[$k] = phpgw_xmlrpc_encode($v);
}
$xmlrpc_val->addStruct($arr);
break;
case 'integer':
$xmlrpc_val->addScalar($php_val, xmlrpcInt);
break;
case 'double':
$xmlrpc_val->addScalar($php_val, xmlrpcDouble);
break;
case 'string':
$xmlrpc_val->addScalar($php_val, xmlrpcString);
break;
// <G_Giunta_2001-02-29>
// Add support for encoding/decoding of booleans, since they are supported in PHP
case 'boolean':
$xmlrpc_val->addScalar($php_val, xmlrpcBoolean);
break;
// </G_Giunta_2001-02-29>
case 'unknown type':
default:
$xmlrpc_val = False;
break;
}
return $xmlrpc_val;
}
/* The following functions are the system functions for login, logout, etc.
* They are added to the server map at the end of this file.
*/
$GLOBALS['_xmlrpcs_listMethods_sig'] = array(array(xmlrpcArray, xmlrpcString), array(xmlrpcArray));
$GLOBALS['_xmlrpcs_listMethods_doc'] = 'This method lists all the methods that the XML-RPC server knows how to dispatch';
function _xmlrpcs_listMethods($server, $m)
{
$v = CreateObject('phpgwapi.xmlrpcval');
$dmap = $server->dmap;
$outAr = array();
for(reset($dmap); list($key, $val) = each($dmap); )
{
$outAr[] = CreateObject('phpgwapi.xmlrpcval',$key, 'string');
}
$dmap = $GLOBALS['_xmlrpcs_dmap'];
for(reset($dmap); list($key, $val) = each($dmap); )
{
$outAr[] = CreateObject('phpgwapi.xmlrpcval',$key, 'string');
}
$v->addArray($outAr);
return CreateObject('phpgwapi.xmlrpcresp',$v);
}
$GLOBALS['_xmlrpcs_methodSignature_sig']=array(array(xmlrpcArray, xmlrpcString));
$GLOBALS['_xmlrpcs_methodSignature_doc']='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
function _xmlrpcs_methodSignature($server, $m)
{
$methName = $m->getParam(0);
$methName = $methName->scalarval();
if (preg_match('/'."^system\.".'/', $methName))
{
$dmap = $GLOBALS['_xmlrpcs_dmap'];
$sysCall = 1;
}
else
{
$dmap = $server->dmap;
$sysCall = 0;
}
// print "<!-- ${methName} -->\n";
if (isset($dmap[$methName]))
{
if ($dmap[$methName]['signature'])
{
$sigs = array();
$thesigs=$dmap[$methName]['signature'];
for($i=0; $i<sizeof($thesigs); $i++)
{
$cursig = array();
$inSig = $thesigs[$i];
for($j=0; $j<sizeof($inSig); $j++)
{
$cursig[] = CreateObject('phpgwapi.xmlrpcval',$inSig[$j], 'string');
}
$sigs[] = CreateObject('phpgwapi.xmlrpcval',$cursig, 'array');
}
$r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$sigs, 'array'));
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval','undef', 'string'));
}
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',0,$GLOBALS['xmlrpcerr']['introspect_unknown'],$GLOBALS['xmlrpcstr']['introspect_unknown']);
}
return $r;
}
$GLOBALS['_xmlrpcs_methodHelp_sig'] = array(array(xmlrpcString, xmlrpcString));
$GLOBALS['_xmlrpcs_methodHelp_doc'] = 'Returns help text if defined for the method passed, otherwise returns an empty string';
function _xmlrpcs_methodHelp($server, $m)
{
$methName = $m->getParam(0);
$methName = $methName->scalarval();
if (preg_match('/'."^system\.".'/', $methName))
{
$dmap = $GLOBALS['_xmlrpcs_dmap'];
$sysCall=1;
}
else
{
$dmap = $server->dmap;
$sysCall=0;
}
// print "<!-- ${methName} -->\n";
if (isset($dmap[$methName]))
{
if ($dmap[$methName]['docstring'])
{
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval',$dmap[$methName]['docstring']),'string');
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval'), 'string');
}
}
else
{
$r = CreateObject('phpgwapi.xmlrpcresp',0,$GLOBALS['xmlrpcerr']['introspect_unknown'],$GLOBALS['xmlrpcstr']['introspect_unknown']);
}
return $r;
}
$GLOBALS['_xmlrpcs_login_sig'] = array(array(xmlrpcStruct,xmlrpcStruct));
$GLOBALS['_xmlrpcs_login_doc'] = 'eGroupWare client or server login via XML-RPC';
function _xmlrpcs_login($server,$m)
{
$rdata = $m->getParam(0);
$data = $rdata->scalarval();
if($data['server_name'])
{
$server_name = $data['server_name']->scalarval();
}
if($data['domain'])
{
$domain = $data['domain']->scalarval();
}
$username = $data['username']->scalarval();
$password = $data['password']->scalarval();
if($server_name)
{
list($sessionid,$kp3) = $GLOBALS['egw']->session->create($username.'@'.$server_name,$password,"text");
}
else
{
if($domain)
{
$user = $username.'@'.$domain;
}
else
{
$user = $username;
}
$GLOBALS['login'] = $user;
$sessionid = $GLOBALS['egw']->session->create($user,$password,"text");
$kp3 = $GLOBALS['egw']->session->kp3;
$domain = $GLOBALS['egw']->session->account_domain;
}
if($sessionid && $kp3)
{
$rtrn['domain'] = CreateObject('phpgwapi.xmlrpcval',$domain,'string');
$rtrn['sessionid'] = CreateObject('phpgwapi.xmlrpcval',$sessionid,'string');
$rtrn['kp3'] = CreateObject('phpgwapi.xmlrpcval',$kp3,'string');
}
else
{
$rtrn['GOAWAY'] = CreateObject('phpgwapi.xmlrpcval','XOXO','string');
}
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$rtrn,'struct'));
}
$GLOBALS['_xmlrpcs_logout_sig'] = array(array(xmlrpcStruct,xmlrpcStruct));
$GLOBALS['_xmlrpcs_logout_doc'] = 'eGroupWare client or server logout via XML-RPC';
function _xmlrpcs_logout($server,$m)
{
$rdata = $m->getParam(0);
$data = $rdata->scalarval();
$sessionid = $data['sessionid']->scalarval();
$kp3 = $data['kp3']->scalarval();
$later = $GLOBALS['egw']->session->destroy($sessionid,$kp3);
if ($later)
{
$rtrn['GOODBYE'] = CreateObject('phpgwapi.xmlrpcval','XOXO','string');
}
else
{
/* This never happens, yet */
$rtrn['OOPS'] = CreateObject('phpgwapi.xmlrpcval','WHAT?','string');
}
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$rtrn,'struct'));
}
$GLOBALS['_xmlrpcs_phpgw_api_version_sig'] = array(array(xmlrpcString));
$GLOBALS['_xmlrpcs_phpgw_api_version_doc'] = 'Returns the eGroupWare API version';
function _xmlrpcs_phpgw_api_version($server,$m)
{
$version = $GLOBALS['egw_info']['server']['versions']['phpgwapi'];
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$version,'string'));
}
/*
$GLOBALS['_xmlrpcs_listApps_sig'] = array(array(xmlrpcStruct,xmlrpcString));
$GLOBALS['_xmlrpcs_listApps_doc'] = 'Returns a list of installed phpgw apps';
function _xmlrpcs_listApps($server,$m)
{
$m->getParam(0);
$GLOBALS['egw']->db->query("SELECT * FROM egw_applications WHERE app_enabled<3",__LINE__,__FILE__);
if($GLOBALS['egw']->db->num_rows())
{
while($GLOBALS['egw']->db->next_record())
{
$name = $GLOBALS['egw']->db->f('app_name');
$title = $GLOBALS['egw']->db->f('app_title');
$status = $GLOBALS['egw']->db->f('app_enabled');
$version= $GLOBALS['egw']->db->f('app_version');
$apps[$name] = CreateObject('phpgwapi.xmlrpcval',
array(
'title' => CreateObject('phpgwapi.xmlrpcval',$title,'string'),
'name' => CreateObject('phpgwapi.xmlrpcval',$name,'string'),
'status' => CreateObject('phpgwapi.xmlrpcval',$status,'string'),
'version'=> CreateObject('phpgwapi.xmlrpcval',$version,'string')
),
'struct'
);
}
}
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$apps, 'struct'));
}
*/
$GLOBALS['_xmlrpcs_egw_time_sig'] = array(array(xmlrpcStruct));
$GLOBALS['_xmlrpcs_egw_time_doc'] = 'returns system-time and -timezone and if loged in user-time and timezone';
function _xmlrpcs_time($server,$m)
{
$return = array(
'system' => $GLOBALS['server']->date2iso8601(time()),
'system_tz_offset' => (int) date('Z'),
);
if ($GLOBALS['server']->authed)
{
$tz_offset_s = 3600 * (int) $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
$return += array(
'user' => $GLOBALS['server']->date2iso8601(time()+$tz_offset_s),
'user_tz_offset' => (int) date('Z') + $tz_offset_s,
);
}
return CreateObject(
'phpgwapi.xmlrpcresp',
$GLOBALS['server']->build_resp($return,true)
);
}
/* Add the system functions to the server map */
$GLOBALS['_xmlrpcs_dmap'] = array(
'system.listMethods' => array(
'function' => '_xmlrpcs_listMethods',
'signature' => $GLOBALS['_xmlrpcs_listMethods_sig'],
'docstring' => $GLOBALS['_xmlrpcs_listMethods_doc']
),
'system.methodHelp' => array(
'function' => '_xmlrpcs_methodHelp',
'signature' => $GLOBALS['_xmlrpcs_methodHelp_sig'],
'docstring' => $GLOBALS['_xmlrpcs_methodHelp_doc']
),
'system.methodSignature' => array(
'function' => '_xmlrpcs_methodSignature',
'signature' => $GLOBALS['_xmlrpcs_methodSignature_sig'],
'docstring' => $GLOBALS['_xmlrpcs_methodSignature_doc']
),
'system.login' => array(
'function' => '_xmlrpcs_login',
'signature' => $GLOBALS['_xmlrpcs_login_sig'],
'docstring' => $GLOBALS['_xmlrpcs_login_doc']
),
'system.logout' => array(
'function' => '_xmlrpcs_logout',
'signature' => $GLOBALS['_xmlrpcs_logout_sig'],
'docstring' => $GLOBALS['_xmlrpcs_logout_doc']
),
'system.phpgw_api_version' => array(
'function' => '_xmlrpcs_phpgw_api_version',
'signature' => $GLOBALS['_xmlrpcs_phpgw_api_version_sig'],
'docstring' => $GLOBALS['_xmlrpcs_phpgw_api_version_doc']
),
/*
'system.listApps' => array(
'function' => '_xmlrpcs_listApps',
'signature' => $GLOBALS['_xmlrpcs_listApps_sig'],
'docstring' => $GLOBALS['_xmlrpcs_listApps_doc']
),
*/
'system.time' => array(
'function' => '_xmlrpcs_time',
'signature' => $GLOBALS['_xmlrpcs_egw_time_sig'],
'docstring' => $GLOBALS['_xmlrpcs_egw_time_doc']
)
);
$GLOBALS['_xmlrpc_debuginfo'] = '';
function xmlrpc_debugmsg($m)
{
$GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
}
?>

View File

@ -1,629 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare xmlrpc interop functions *
* http://www.egroupware.org *
* Portions of code from server.php by Edd Dumbill <edd@usefulinc.com> *
* part of the xml-rpc for php library *
* http://sourceforge.net/projects/phpxmlrpc/ *
* Incorporated for egroupware by Miles Lott <milos@groupwhere.org> *
* ------------------------------------------------------------------------ *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
// a PHP version
// of the state-number server
// send me an integer and i'll sell you a state
$stateNames = array(
'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',
'Colorado', 'Columbia', 'Connecticut', 'Delaware', 'Florida',
'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas',
'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan',
'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada',
'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina',
'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island',
'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont',
'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'
);
$findstate_sig = array(array(xmlrpcString, xmlrpcInt));
$findstate_doc = 'When passed an integer between 1 and 51 returns the
name of a US state, where the integer is the index of that state name
in an alphabetic order.';
function findstate($m)
{
$err='';
// get the first param
$sno=$m->getParam(0);
// if it's there and the correct type
if (isset($sno) && ($sno->scalartyp()=='int'))
{
// extract the value of the state number
$snv=$sno->scalarval();
// look it up in our array (zero-based)
if (isset($GLOBALS['stateNames'][$snv-1]))
{
$sname=$GLOBALS['stateNames'][$snv-1];
}
else
{
// not, there so complain
$err="I don't have a state for the index '" . $snv . "'";
}
}
else
{
// parameter mismatch, complain
$err='One integer parameter required';
}
// if we generated an error, create an error return response
if ($err)
{
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
}
else
{
// otherwise, we create the right response
// with the state name
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$sname));
}
}
$addtwo_sig=array(array(xmlrpcInt, xmlrpcInt, xmlrpcInt));
$addtwo_doc='Add two integers together and return the result';
function addtwo($m)
{
$s=$m->getParam(0);
$t=$m->getParam(1);
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()+$t->scalarval(),'int'));
}
$addtwodouble_sig=array(array(xmlrpcDouble, xmlrpcDouble, xmlrpcDouble));
$addtwodouble_doc='Add two doubles together and return the result';
function addtwodouble($m)
{
$s=$m->getParam(0);
$t=$m->getParam(1);
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()+$t->scalarval(),'double'));
}
$stringecho_sig=array(array(xmlrpcString, xmlrpcString));
$stringecho_doc='Accepts a string parameter, returns the string.';
function stringecho($m)
{
// just sends back a string
$s=$m->getParam(0);
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s->scalarval()));
}
$echoback_sig=array(array(xmlrpcString, xmlrpcString));
$echoback_doc='Accepts a string parameter, returns the entire incoming payload';
function echoback($m)
{
// just sends back a string with what i got
// send to me, just escaped, that's all
//
// $m is an incoming message
$s="I got the following message:\n" . $m->serialize();
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$s));
}
$echosixtyfour_sig=array(array(xmlrpcString, xmlrpcBase64));
$echosixtyfour_doc='Accepts a base64 parameter and returns it decoded as a string';
function echosixtyfour($m)
{
// accepts an encoded value, but sends it back
// as a normal string. this is to test base64 encoding
// is working as expected
$incoming=$m->getParam(0);
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$incoming->scalarval(), 'string'));
}
$bitflipper_sig=array(array(xmlrpcArray, xmlrpcArray));
$bitflipper_doc='Accepts an array of booleans, and returns them inverted';
function bitflipper($m)
{
$v = $m->getParam(0);
$sz = $v->arraysize();
$rv = CreateObject('phpgwapi.xmlrpcval',array(), xmlrpcArray);
for($j=0; $j<$sz; $j++)
{
$b = $v->arraymem($j);
if ($b->scalarval())
{
$rv->addScalar(False, 'boolean');
}
else
{
$rv->addScalar(True, 'boolean');
}
}
return CreateObject('phpgwapi.xmlrpcresp',$rv);
}
// Sorting demo
//
// send me an array of structs thus:
//
// Dave 35
// Edd 45
// Fred 23
// Barney 37
//
// and I'll return it to you in sorted order
function agesorter_compare($a, $b)
{
// don't even ask me _why_ these come padded with
// hyphens, I couldn't tell you :p
$a = str_replace('-', '', $a);
$b = str_replace('-', '', $b);
if ($GLOBALS['agesorter_arr'][$a]==$agesorter[$b])
{
return 0;
}
return ($GLOBALS['agesorter_arr'][$a] > $GLOBALS['agesorter_arr'][$b]) ? -1 : 1;
}
$agesorter_sig=array(array(xmlrpcArray, xmlrpcArray));
$agesorter_doc='Send this method an array of [string, int] structs, eg:
<PRE>
Dave 35
Edd 45
Fred 23
Barney 37
</PRE>
And the array will be returned with the entries sorted by their numbers.
';
function agesorter($m)
{
global $s;
xmlrpc_debugmsg("Entering 'agesorter'");
// get the parameter
$sno = $m->getParam(0);
// error string for [if|when] things go wrong
$err = '';
// create the output value
$v = CreateObject('phpgwapi.xmlrpcval');
$agar = array();
if (isset($sno) && $sno->kindOf()=='array')
{
$max = $sno->arraysize();
// TODO: create debug method to print can work once more
// print "<!-- found $max array elements -->\n";
for($i=0; $i<$max; $i++)
{
$rec = $sno->arraymem($i);
if ($rec->kindOf()!='struct')
{
$err = 'Found non-struct in array at element ' . $i;
break;
}
// extract name and age from struct
$n = $rec->structmem('name');
$a = $rec->structmem('age');
// $n and $a are xmlrpcvals,
// so get the scalarval from them
$agar[$n->scalarval()] = $a->scalarval();
}
$GLOBALS['agesorter_arr'] = $agar;
// hack, must make global as uksort() won't
// allow us to pass any other auxilliary information
uksort($GLOBALS['agesorter_arr'], agesorter_compare);
$outAr = array();
while (list($key,$val) = each($GLOBALS['agesorter_arr']))
{
// recreate each struct element
$outAr[] = CreateObject('phpgwapi.xmlrpcval',array(
'name' => CreateObject('phpgwapi.xmlrpcval',$key),
'age' => CreateObject('phpgwapi.xmlrpcval',$val, 'int')
),
'struct'
);
}
// add this array to the output value
$v->addArray($outAr);
}
else
{
$err = 'Must be one parameter, an array of structs';
}
if ($err)
{
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
}
else
{
return CreateObject('phpgwapi.xmlrpcresp',$v);
}
}
// signature and instructions, place these in the dispatch map
$mail_send_sig = array(
array(
xmlrpcBoolean, xmlrpcString, xmlrpcString,
xmlrpcString, xmlrpcString, xmlrpcString,
xmlrpcString, xmlrpcString
)
);
$mail_send_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)
<BR>recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.
<BR>subject is a string, the subject of the message.
<BR>sender is a string, it\'s the email address of the person sending the message. This string can not be
a comma-separated list, it must contain a single email address only.
text is a string, it contains the body of the message.
<BR>mimetype, a string, is a standard MIME type, for example, text/plain.
';
// WARNING; this functionality depends on the sendmail -t option
// it may not work with Windows machines properly; particularly
// the Bcc option. Sneak on your friends at your own risk!
function mail_send($m)
{
$err = '';
$mTo = $m->getParam(0);
$mSub = $m->getParam(1);
$mBody = $m->getParam(2);
$mFrom = $m->getParam(3);
$mCc = $m->getParam(4);
$mBcc = $m->getParam(5);
$mMime = $m->getParam(6);
if ($mTo->scalarval() == '')
{
$err = "Error, no 'To' field specified";
}
if ($mFrom->scalarval() == '')
{
$err = "Error, no 'From' field specified";
}
$msghdr = 'From: ' . $mFrom->scalarval() . "\n";
$msghdr .= 'To: '. $mTo->scalarval() . "\n";
if ($mCc->scalarval()!='')
{
$msghdr .= 'Cc: ' . $mCc->scalarval(). "\n";
}
if ($mBcc->scalarval()!='')
{
$msghdr .= 'Bcc: ' . $mBcc->scalarval(). "\n";
}
if ($mMime->scalarval()!='')
{
$msghdr .= 'Content-type: ' . $mMime->scalarval() . "\n";
}
$msghdr .= 'X-Mailer: XML-RPC for PHP mailer 1.0';
if ($err == '')
{
if (!mail('', $mSub->scalarval(), $mBody->scalarval(), $msghdr))
{
$err = 'Error, could not send the mail.';
}
}
if ($err)
{
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval'), $GLOBALS['xmlrpcerruser'], $err);
}
else
{
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval','true', xmlrpcBoolean));
}
}
$v1_arrayOfStructs_sig = array(array(xmlrpcInt, xmlrpcArray));
$v1_arrayOfStructs_doc = 'This handler takes a single parameter, an array of structs, each of which contains at least three elements named moe, larry and curly, all <i4>s. Your handler must add all the struct elements named curly and return the result.';
function v1_arrayOfStructs($m)
{
$sno = $m->getParam(0);
$numcurly = 0;
for($i=0; $i<$sno->arraysize(); $i++)
{
$str = $sno->arraymem($i);
$str->structreset();
while(list($key,$val) = $str->structeach())
{
if ($key == 'curly')
{
$numcurly += $val->scalarval();
}
}
}
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$numcurly, 'int'));
}
$v1_easyStruct_sig = array(array(xmlrpcInt, xmlrpcStruct));
$v1_easyStruct_doc = 'This handler takes a single parameter, a struct, containing at least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
function v1_easyStruct($m)
{
$sno = $m->getParam(0);
$moe = $sno->structmem('moe');
$larry = $sno->structmem('larry');
$curly = $sno->structmem('curly');
$num = $moe->scalarval() + $larry->scalarval() + $curly->scalarval();
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$num, 'int'));
}
$v1_echoStruct_sig=array(array(xmlrpcStruct, xmlrpcStruct));
$v1_echoStruct_doc='This handler takes a single parameter, a struct. Your handler must return the struct.';
function v1_echoStruct($m)
{
$sno=$m->getParam(0);
return CreateObject('phpgwapi.xmlrpcresp',$sno);
}
$v1_manyTypes_sig = array(
array(
xmlrpcArray, xmlrpcInt, xmlrpcBoolean,
xmlrpcString, xmlrpcDouble, xmlrpcDateTime,
xmlrpcBase64
)
);
$v1_manyTypes_doc = 'This handler takes six parameters, and returns an array containing all the parameters.';
function v1_manyTypes($m)
{
return CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval',array(
$m->getParam(0),
$m->getParam(1),
$m->getParam(2),
$m->getParam(3),
$m->getParam(4),
$m->getParam(5)
),
'array'
));
}
$v1_moderateSizeArrayCheck_sig = array(array(xmlrpcString, xmlrpcArray));
$v1_moderateSizeArrayCheck_doc = 'This handler takes a single parameter, which is an array containing between 100 and 200 elements. Each of the items is a string, your handler must return a string containing the concatenated text of the first and last elements.';
function v1_moderateSizeArrayCheck($m)
{
$ar = $m->getParam(0);
$sz = $ar->arraysize();
$first = $ar->arraymem(0);
$last = $ar->arraymem($sz-1);
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',$first->scalarval() . $last->scalarval(), "string"));
}
$v1_simpleStructReturn_sig = array(array(xmlrpcStruct, xmlrpcInt));
$v1_simpleStructReturn_doc = 'This handler takes one parameter, and returns a struct containing three elements, times10, times100 and times1000, the result of multiplying the number by 10, 100 and 1000.';
function v1_simpleStructReturn($m)
{
$sno=$m->getParam(0);
$v=$sno->scalarval();
return CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval',array(
'times10' => CreateObject('phpgwapi.xmlrpcval',$v*10, 'int'),
'times100' => CreateObject('phpgwapi.xmlrpcval',$v*100, 'int'),
'times1000' => CreateObject('phpgwapi.xmlrpcval',$v*1000, 'int')
),
'struct'
));
}
$v1_nestedStruct_sig = array(array(xmlrpcInt, xmlrpcStruct));
$v1_nestedStruct_doc = 'This handler takes a single parameter, a struct, that models a daily calendar. At the top level, there is one struct for each year. Each year is broken down into months, and months into days. Most of the days are empty in the struct you receive, but the entry for April 1, 2000 contains a least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
function v1_nestedStruct($m)
{
$sno=$m->getParam(0);
$twoK=$sno->structmem('2000');
$april=$twoK->structmem('04');
$fools=$april->structmem('01');
$curly=$fools->structmem('curly');
$larry=$fools->structmem('larry');
$moe=$fools->structmem('moe');
return CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',
$curly->scalarval() + $larry->scalarval() + $moe->scalarval(), 'int'
));
}
$v1_countTheEntities_sig=array(array(xmlrpcStruct, xmlrpcString));
$v1_countTheEntities_doc='This handler takes a single parameter, a string, that contains any number of predefined entities, namely &lt;, &gt;, &amp; \' and ".<BR>Your handler must return a struct that contains five fields, all numbers: ctLeftAngleBrackets, ctRightAngleBrackets, ctAmpersands, ctApostrophes, ctQuotes.';
function v1_countTheEntities($m)
{
$sno=$m->getParam(0);
$str=$sno->scalarval();
$gt=0; $lt=0; $ap=0; $qu=0; $amp=0;
for($i=0; $i<strlen($str); $i++)
{
$c=substr($str, $i, 1);
switch($c)
{
case '>':
$gt++;
break;
case '<':
$lt++;
break;
case '"':
$qu++;
break;
case "'":
$ap++;
break;
case '&':
$amp++;
break;
default:
break;
}
}
return CreateObject('phpgwapi.xmlrpcresp',
CreateObject('phpgwapi.xmlrpcval',array(
'ctLeftAngleBrackets' => CreateObject('phpgwapi.xmlrpcval',$lt, 'int'),
'ctRightAngleBrackets' => CreateObject('phpgwapi.xmlrpcval',$gt, 'int'),
'ctAmpersands' => CreateObject('phpgwapi.xmlrpcval',$amp, 'int'),
'ctApostrophes' => CreateObject('phpgwapi.xmlrpcval',$ap, 'int'),
'ctQuotes' => CreateObject('phpgwapi.xmlrpcval',$qu, 'int')
),
'struct'
));
}
// trivial interop tests
// http://www.xmlrpc.com/stories/storyReader$1636
$i_echoString_sig=array(array(xmlrpcString, xmlrpcString));
$i_echoString_doc='Echoes string.';
$i_echoStringArray_sig=array(array(xmlrpcArray, xmlrpcArray));
$i_echoStringArray_doc='Echoes string array.';
$i_echoInteger_sig=array(array(xmlrpcInt, xmlrpcInt));
$i_echoInteger_doc='Echoes integer.';
$i_echoIntegerArray_sig=array(array(xmlrpcArray, xmlrpcArray));
$i_echoIntegerArray_doc='Echoes integer array.';
$i_echoFloat_sig=array(array(xmlrpcDouble, xmlrpcDouble));
$i_echoFloat_doc='Echoes float.';
$i_echoFloatArray_sig=array(array(xmlrpcArray, xmlrpcArray));
$i_echoFloatArray_doc='Echoes float array.';
$i_echoStruct_sig=array(array(xmlrpcStruct, xmlrpcStruct));
$i_echoStruct_doc='Echoes struct.';
$i_echoStructArray_sig=array(array(xmlrpcArray, xmlrpcArray));
$i_echoStructArray_doc='Echoes struct array.';
$i_echoValue_doc='Echoes any value back.';
$i_echoBase64_sig=array(array(xmlrpcBase64, xmlrpcBase64));
$i_echoBase64_doc='Echoes base64.';
$i_echoDate_sig=array(array(xmlrpcDateTime, xmlrpcDateTime));
$i_echoDate_doc='Echoes dateTime.';
function i_echoParam($m)
{
$s = $m->getParam(0);
return CreateObject('phpgwapi.xmlrpcresp',$s);
}
function i_echoString($m)
{
return i_echoParam($m);
}
function i_echoInteger($m)
{
return i_echoParam($m);
}
function i_echoFloat($m)
{
return i_echoParam($m);
}
function i_echoStruct($m)
{
return i_echoParam($m);
}
function i_echoStringArray($m)
{
return i_echoParam($m);
}
function i_echoIntegerArray($m)
{
return i_echoParam($m);
}
function i_echoFloatArray($m)
{
return i_echoParam($m);
}
function i_echoStructArray($m)
{
return i_echoParam($m);
}
function i_echoValue($m)
{
return i_echoParam($m);
}
function i_echoBase64($m)
{
return i_echoParam($m);
}
function i_echoDate($m)
{
return i_echoParam($m);
}
$i_whichToolkit_doc = 'Returns a struct containing the following strings: toolkitDocsUrl, toolkitName, toolkitVersion, toolkitOperatingSystem.';
function i_whichToolkit($m)
{
$ret = array(
'toolkitDocsUrl' => 'http://xmlrpc.usefulinc.com/php.html',
'toolkitName' => $GLOBALS['xmlrpcName'],
'toolkitVersion' => $GLOBALS['xmlrpcVersion'],
'toolkitOperatingSystem' => $GLOBALS['SERVER_SOFTWARE']
);
return CreateObject('phpgwapi.xmlrpcresp',phpgw_xmlrpc_encode($ret));
}
$server->add_to_map('examples.getStateName', 'findstate',$findstate_sig,$findstate_doc);
$server->add_to_map('examples.sortByAge', 'agesorter',$agesorter_sig,$agesorter_doc);
$server->add_to_map('examples.addtwo', 'addtwo',$addtwo_sig,$addtwo_doc);
$server->add_to_map('examples.addtwodouble', 'addtwodouble',$addtwodouble_sig,$addtwodouble_doc);
$server->add_to_map('examples.stringecho', 'stringecho',$stringecho_sig,$stringecho_doc);
$server->add_to_map('examples.echo', 'echoback',$echoback_sig,$echoback_doc);
$server->add_to_map('examples.decode64', 'echosixtyfour',$echosixtyfour_sig,$echosixtyfour_doc);
$server->add_to_map('examples.invertBooleans', 'bitflipper',$bitflipper_sig,$bitflipper_doc);
$server->add_to_map('mail.send', 'mail_send',$mail_send_sig,$mail_send_doc);
$server->add_to_map('validator1.arrayOfStructsTest', 'v1_arrayOfStructs',$v1_arrayOfStructs_sig,$v1_arrayOfStructs_doc);
$server->add_to_map('validator1.easyStructTest', 'v1_easyStruct',$v1_easyStruct_sig,$v1_easyStruct_doc);
$server->add_to_map('validator1.echoStructTest', 'v1_echoStruct',$v1_echoStruct_sig,$v1_echoStruct_doc);
$server->add_to_map('validator1.manyTypesTest', 'v1_manyTypes',$v1_manyTypes_sig,$v1_manyTypes_doc);
$server->add_to_map('validator1.moderateSizeArrayCheck','v1_moderateSizeArrayCheck',$v1_moderateSizeArrayCheck_sig,$v1_moderateSizeArrayCheck_doc);
$server->add_to_map('validator1.simpleStructReturnTest','v1_simpleStructReturn',$v1_simpleStructReturn_sig,$v1_simpleStructReturn_doc);
$server->add_to_map('validator1.nestedStructTest', 'v1_nestedStruct',$v1_nestedStruct_sig,$v1_nestedStruct_doc);
$server->add_to_map('validator1.countTheEntities', 'v1_countTheEntities',$v1_countTheEntities_sig,$v1_countTheEntities_doc);
$server->add_to_map('interopEchoTests.echoString', 'i_echoString',$i_echoString_sig,$i_echoString_doc);
$server->add_to_map('interopEchoTests.echoStringArray', 'i_echoStringArray',$i_echoStringArray_sig,$i_echoStringArray_doc);
$server->add_to_map('interopEchoTests.echoInteger', 'i_echoInteger',$i_echoInteger_sig,$i_echoInteger_doc);
$server->add_to_map('interopEchoTests.echoIntegerArray','i_echoIntegerArray',$i_echoIntegerArray_sig,$i_echoIntegerArray_doc);
$server->add_to_map('interopEchoTests.echoFloat', 'i_echoFloat',$i_echoFloat_sig,$i_echoFloat_doc);
$server->add_to_map('interopEchoTests.echoFloatArray', 'i_echoFloatArray',$i_echoFloatArray_sig,$i_echoFloatArray_doc);
$server->add_to_map('interopEchoTests.echoStruct', 'i_echoStruct',$i_echoStruct_sig,$i_echoStruct_doc);
$server->add_to_map('interopEchoTests.echoStructArray', 'i_echoStructArray',$i_echoStructArray_sig,$i_echoStructArray_doc);
$server->add_to_map('interopEchoTests.echoValue', 'i_echoValue','',$i_echoValue_doc);
$server->add_to_map('interopEchoTests.echoBase64', 'i_echoBase64',$i_echoBase64_sig,$i_echoBase64_doc);
$server->add_to_map('interopEchoTests.echoDate', 'i_echoDate',$i_echoDate_sig,$i_echoDate_doc);
$server->add_to_map('interopEchoTests.whichToolkit', 'i_whichToolkit','',$i_whichToolkit_doc);
// that should do all we need!
?>

View File

@ -1,102 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - XML-RPC Test App *
* http://www.egroupware.org *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
$phpgw_info = array();
$GLOBALS['phpgw_info']['flags'] = array(
'noheader' => True,
'nonavbar' => True,
'currentapp' => 'home',
'noapi' => True
);
include('./inc/functions.inc.php');
include(PHPGW_SERVER_ROOT . 'phpgwapi/inc/xml_functions.inc.php');
/* Check header and authentication */
if (!$GLOBALS['phpgw_setup']->auth('Config'))
{
Header('Location: index.php');
exit;
}
// Does not return unless user is authorized
$tpl_root = $GLOBALS['phpgw_setup']->html->setup_tpl_dir('setup');
$setup_tpl = CreateObject('phpgwapi.Template',$tpl_root);
$setup_tpl->set_file(array(
'T_head' => 'head.tpl',
'T_footer' => 'footer.tpl'
));
$setup_tpl->set_block('T_footer','footer','footer');
$host = 'us.egroupware.org';
$path = '/cvsdemo/xmlrpc.php';
$GLOBALS['phpgw_setup']->html->show_header(lang('Application List'),True);
/* Login as demo */
$login = CreateObject(
'phpgwapi.xmlrpcmsg',
'system.login',
array(
CreateObject(
'phpgwapi.xmlrpcval',
array(
'domain' => CreateObject('phpgwapi.xmlrpcval','default','string'),
'username' => CreateObject('phpgwapi.xmlrpcval','demo','string'),
'password' => CreateObject('phpgwapi.xmlrpcval','guest','string')
),
'struct'
)
)
);
echo '<pre>' . htmlentities($login->serialize()) . "</pre>\n";
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
$c->setDebug(1);
$r = $c->send($login);
$v = $r->value();
$result = xmlrpc_decode($v);
/* Get applist */
$f = CreateObject('phpgwapi.xmlrpcmsg','system.listApps','');
echo '<pre>' . htmlentities($f->serialize()) . "</pre>\n";
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
$c->setDebug(1);
$c->username = $result['sessionid'];
$c->password = $result['kp3'];
$r = $c->send($f);
/* Logout */
$logout = CreateObject(
'phpgwapi.xmlrpcmsg',
'system.logout',
array(
CreateObject(
'phpgwapi.xmlrpcval',
array(
'sessionid' => CreateObject('phpgwapi.xmlrpcval',$result['sessionid'],'string'),
'kp3' => CreateObject('phpgwapi.xmlrpcval',$result['kp3'],'string')
),
'struct'
)
)
);
echo '<pre>' . htmlentities($logout->serialize()) . "</pre>\n";
$c = CreateObject('phpgwapi.xmlrpc_client',$path,$host,80);
$c->setDebug(1);
$r = $c->send($logout);
$v = $r->value();
$GLOBALS['phpgw_setup']->html->show_footer();
?>

View File

@ -1,95 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - SOAP Server *
* http://www.egroupware.org *
* Written by Miles Lott <milos@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
$GLOBALS['egw_info'] = array(
'flags' => array(
'disable_Template_class' => True,
'currentapp' => 'login',
'noheader' => True,
'disable_Template_class' => True
)
);
include('./header.inc.php');
include_once(EGW_API_INC . '/xml_functions.inc.php'); // not sure that's neccessary, but I have no way to test
include_once(EGW_API_INC . '/soap_functions.inc.php');
$GLOBALS['server'] = CreateObject('phpgwapi.soap_server');
/* _debug_array($GLOBALS['server']);exit; */
/* include(EGW_API_INC . '/soaplib.soapinterop.php'); */
if (!$GLOBALS['egw_info']['server']['soap_enabled'])
{
$GLOBALS['server']->make_fault(9999,'soap service is not enabled in the eGroupWare system configuration');
$GLOBALS['server']->service($GLOBALS['server']->fault());
exit;
}
/* Note: this command only available natively in Apache (Netscape/iPlanet/SunONE in php >= 4.3.3) */
if(!function_exists('getallheaders'))
{
function getallheaders()
{
settype($headers,'array');
foreach($_SERVER as $h => $v)
{
if(preg_match('/HTTP_(.+)/',$h,$hp))
{
$headers[$hp[1]] = $v;
}
}
return $headers;
}
}
$headers = getallheaders();
if(strpos($headers['Authorization'],'Basic') !== false)
{
$tmp = $headers['Authorization'];
$tmp = str_replace(' ','',$tmp);
$tmp = str_replace('Basic','',$tmp);
$auth = base64_decode(trim($tmp));
list($sessionid,$kp3) = explode(':',$auth);
if($GLOBALS['egw']->session->verify($sessionid,$kp3))
{
$GLOBALS['server']->authed = True;
}
elseif($GLOBALS['egw']->session->verify_server($sessionid,$kp3))
{
$GLOBALS['server']->authed = True;
}
}
$GLOBALS['server']->add_to_map(
'system_login',
array('soapstruct'),
array('soapstruct')
);
$GLOBALS['server']->add_to_map(
'system_logout',
array('soapstruct'),
array('soapstruct')
);
if(function_exists('system_listapps'))
{
$GLOBALS['server']->add_to_map(
'system_listApps',
array(),
array('soapstruct')
);
}
$GLOBALS['server']->service($HTTP_RAW_POST_DATA);

View File

@ -1,90 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare xmlrpc server *
* http://www.egroupware.org *
* This file written by Miles Lott <milos@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/* $Source$ */
/*list($usec, $sec) = explode(" ", microtime());
$GLOBALS['concisus']['script_start'] = ((float)$usec + (float)$sec);*/
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'login',
'noheader' => True,
'disable_Template_class' => True
)
);
include('./header.inc.php');
include_once(EGW_API_INC . '/xml_functions.inc.php');
include_once(EGW_API_INC . '/soap_functions.inc.php'); // not sure that's neccessary, but I have no way to test
//viniciuscb: a secure way to know if we're in a xmlrpc call...
$GLOBALS['egw_info']['server']['xmlrpc'] = true;
$server = CreateObject('phpgwapi.xmlrpc_server');
/* uncomment here if you want to show all of the testing functions for compatibility */
//include(EGW_API_INC . '/xmlrpc.interop.php');
if (!$GLOBALS['egw_info']['server']['xmlrpc_enabled'])
{
$server->xmlrpc_error(9999,'xmlrpc service is not enabled in the eGroupWare system configuration');
exit;
}
/* Note: this command only available natively in Apache (Netscape/iPlanet/SunONE in php >= 4.3.3) */
if(!function_exists('getallheaders'))
{
function getallheaders()
{
settype($headers,'array');
foreach($_SERVER as $h => $v)
{
if(preg_match('/HTTP_(.+)/',$h,$hp))
{
$headers[$hp[1]] = $v;
}
}
return $headers;
}
}
$headers = getallheaders();
//print_r($headers);
$isodate = $headers['isoDate'] ? $headers['isoDate'] : $headers['isodate'];
$isodate = ($isodate == 'simple') ? True : False;
$server->setSimpleDate($isodate);
$auth_header = $headers['Authorization'] ? $headers['Authorization'] : $headers['authorization'];
if(preg_match('/Basic *([^ ]*)/i',$auth_header,$auth))
{
list($sessionid,$kp3) = explode(':',base64_decode($auth[1]));
//echo "auth='$auth[1]', sessionid='$sessionid', kp3='$kp3'\n";
}
else
{
$sessionid = get_var('sessionid',array('COOKIE','GET'));
$kp3 = get_var('kp3',array('COOKIE','GET'));
}
$server->authed = $GLOBALS['egw']->session->verify($sessionid,$kp3);
if (!$server->authed and isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW']))
{
$authed = $GLOBALS['egw']->session->create($login.'@'.$domain, $_SERVER['PHP_AUTH_PW'], 'text');
if ($authed)
{
$server->authed = true;
}
}
$server->service($_SERVER['HTTP_RAW_POST_DATA']);